Documentation

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

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

Events