Management API and webhooks
Connect a CRM or ERP: read licences, orders and organisations, issue licences, order renewals, and receive signed webhooks when they change.
The management API lets a system you run -- a CRM, an ERP, a billing tool -- read what this platform knows about your licences, orders and organisations, issue licences, and place maintenance renewal orders. Outbound webhooks tell that system when something changed, signed so it can trust the message.
Both are for the platform's own staff and the integrators they authorise. Customers use the portal and their personal API tokens.
Authentication
Every request carries a management key as a bearer token: Authorization: Bearer lpk_... . Keys are created in the admin panel under System > API keys, shown once at creation, and revocable at any time. A key carries scopes and can be given an expiry.
Unknown, revoked and expired keys are all answered with 401 and the same body. A key without the scope an endpoint needs is answered 403. Requests are limited per key; a 429 carries a Retry-After header.
Scopes
- licences:read -- GET /api/v1/manage/licences and /licences/{reference}
- licences:write -- POST /api/v1/manage/licences and /licences/{reference}/renewal-orders
- orders:read -- GET /api/v1/manage/orders and /orders/{number}; includes the billing email
- customers:read -- GET /api/v1/manage/organisations and /organisations/{public_id}
What is returned, and what never is
Responses carry public ids and references: an organisation's public id, a customer's public id (the value that rides in a licence key as CUSTOMER), licence references (LIC-XXXX-XXXX) and order numbers (ORD-XXXX-XXXX). Amounts are integer minor units with a currency.
Licence key text is never returned by this API. The customer receives keys through the portal and by mail. No email address is returned, with one exception: an order's billing email, under orders:read, because it is part of the invoice.
A licence's covered_builds_until_unix is the build-date bound of its maintenance window; zero means every build, forever. Builds released inside the window are the customer's to keep. The licence itself has no end date.
Issuing a licence
POST /api/v1/manage/licences runs the same validation as the admin panel's Issue-a-licence screen and mints an engine-verified key. Name the organisation by public id, the package by its code (slice), the edition by its code, optional add-on codes, seats, a maintenance choice (none, perpetual, or a plan code) and a reason. The reason is stored on the key and in the audit log, under the actor api:<key name>.
POST /api/v1/manage/licences
Authorization: Bearer lpk_...
Content-Type: application/json
{
"organisation": "O4F2A91C7...",
"slice": "pascal",
"edition": "PROFESSIONAL",
"seats": 3,
"addons": ["PDFA"],
"maintenance": "m12",
"email": true,
"reason": "Partner licence under agreement 2026-041"
}
Renewing maintenance
A renewal is an order the customer pays, not a change made by the API. POST /api/v1/manage/licences/{reference}/renewal-orders with a plan code places the order on the same path the admin panel uses and returns the order number and its pay URL. When the order is paid, fulfilment moves the covered-builds window forward and mints the next key version. Pass idempotency_key to make a repeated call return the same order.
Webhooks
An endpoint is created in the admin panel under System > Webhooks: an https URL and the events it wants. Its signing secret is generated there and shown once. Within five minutes of an event the platform POSTs a JSON body to the URL with three headers: X-LumasPDF-Event (the event name), X-LumasPDF-Delivery (a unique delivery id, for de-duplication) and X-LumasPDF-Signature.
X-LumasPDF-Signature: t=1757548800,v1=5f1a...c3e9
# verify:
expected = HMAC_SHA256(secret, t + "." + raw_body) # hex
accept only if expected == v1 (constant-time) and |now - t| <= 300 s
{
"event": "licence.issued",
"event_key": "license_events:8123",
"occurred_at": "2026-09-11 08:00:00.000",
"data": { "kind": "minted", "reason": "...", "actor": "system", "licence": { "reference": "LIC-...", ... } }
}
Delivery rules
- Answer 2xx within 10 seconds to acknowledge. Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours and 24 hours; after six attempts the delivery is marked dead and can be retried by hand from the panel.
- Ten consecutive failures pause the endpoint. Events keep queueing while it is paused; resuming sends them.
- The body is signed exactly as sent. Verify over the raw bytes, not over a re-serialised object.
- Deliveries can arrive more than once and out of order. De-duplicate on X-LumasPDF-Delivery or on event_key, and treat the record inside as a snapshot taken when the event was queued.
- Payloads carry the same fields as the API's read endpoints, and never key text or email addresses.
Events
- licence.issued -- a licence exists and its first key was minted (fulfilment or manual issue)
- licence.updated -- seats, add-ons, edition or covered-builds window changed by staff
- licence.renewed -- a paid renewal moved the covered-builds window forward
- licence.revoked -- contractually revoked; entitlements end, delivered keys keep verifying
- licence.reinstated -- a revocation was lifted
- licence.key_reissued -- a new key version was minted
- licence.event -- any other licence history entry; data.kind carries the raw name
- order.placed, order.paid, order.fulfilled, order.cancelled, order.refunded
- order.refund_requested -- reserved; not emitted yet, refunds are recorded when processed
- order.event -- any other order history entry; data.kind and the status change are included
- payment.recorded -- a gateway confirmed a capture
- payment.failed -- a gateway reported a failure or a rejected checkout signature
- payment.event -- any other payment history entry
- ping -- the test event sent from the panel; carries no business data