Issue a licence
const url = 'https://app.dycrypt.com/o/acme/api/licenses';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"productId":1,"customer":{"name":"Globex Ltd","email":"ops@globex.example"},"validityMonths":12,"graceDays":14,"licenceType":"HYBRID","params":{"maxUsers":250,"edition":"enterprise","features":["sso","audit"]}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://app.dycrypt.com/o/acme/api/licenses \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "productId": 1, "customer": { "name": "Globex Ltd", "email": "ops@globex.example" }, "validityMonths": 12, "graceDays": 14, "licenceType": "HYBRID", "params": { "maxUsers": 250, "edition": "enterprise", "features": [ "sso", "audit" ] } }'Signs a new licence with the product’s key and returns it in full,
including licenseString — the artifact to deliver.
Refused with 403 once the organisation is at its plan’s active-licence
limit. Treat that as “upgrade needed”, not as a broken credential.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
The product whose key signs this licence and whose parameters it must satisfy.
An existing customer…
…or one created inline. Resolved find-or-create by email.
object
Legacy free-text pair with licenseeEmail. Resolves through the same find-or-create path.
The date the licence is dated. Absent = today.
The older name for issueDate. Still accepted.
0 = perpetual. Absent = the product’s default.
Absent = the product’s default.
Absent = the product’s default. Must be one the product allows.
Only meaningful for HYBRID.
Present when the licence binds at issue rather than on first check.
Several machines, for a licence bound to more than one at issue. The
fp claim becomes an array and the schema version rises to 4, so a
verifier that predates multi-machine binding refuses it rather than
reading an array it does not understand as “binds nothing”.
fingerprint is the one-machine spelling and still works; both may be
sent and are combined.
How many machines this licence binds at once. Absent = the product’s figure. Never fewer than the fingerprints signed in.
Values for the product’s declared parameters, keyed by parameter key. Each becomes a claim.
object
Examples
A twelve-month Hybrid licence for a new customer
{ "productId": 1, "customer": { "name": "Globex Ltd", "email": "ops@globex.example" }, "validityMonths": 12, "graceDays": 14, "licenceType": "HYBRID", "params": { "maxUsers": 250, "edition": "enterprise", "features": [ "sso", "audit" ] }}A perpetual licence for an existing customer
{ "productId": 1, "customerId": 42, "validityMonths": 0}Responses
Section titled “Responses”The signed licence.
object
The customer’s name
Signed into the licence as prd.
The nbf claim. Absent means it is valid immediately.
Null for a perpetual licence — the exp claim is omitted entirely.
See the licence-mode guides — Offline verifies alone, Online must check in, Hybrid does both.
How a Hybrid licence first binds to a machine. Only meaningful for HYBRID.
When it bound to a machine. Null means nobody has installed it yet.
How many times an operator released the binding.
How many machines this licence binds at once. Copied from the product at issue.
How many of them are bound right now.
Where the licence is against the calendar and the revocation flag.
PENDING, EXPIRED and REVOKED do not count against plan capacity.
What the field says, beside what the calendar says. NOT_APPLICABLE for
every Offline licence, which is most of them in a typical organisation.
The signed offline window.
How often the application should check in.
Filed away — off the default list and out of renewal. Still verifies in the field.
The person or token that issued it.
The signed payload, decoded. Issuer claims first, then the product’s own parameters.
object
The artifact to deliver: payloadB64url.signatureB64url. This is
what a customer’s application verifies, and its own signature is
its proof.
Free text. Never signed into the licence.
Example
{ "licenceType": "OFFLINE", "activation": "ONLINE", "status": "PENDING", "checkHealth": "NOT_APPLICABLE"}The request is wrong — a bad date, a missing field, a value the product does not declare.
Every failure in this API has this shape and no other.
object
Example
{ "error": "this token does not have licenses:write"}No credential, or one that no longer resolves — revoked, expired, deleted. Replace it.
Every failure in this API has this shape and no other.
object
Example
{ "error": "this token does not have licenses:write"}Missing licenses:write, a read-only role, or the plan’s
active-licence limit reached.
Every failure in this API has this shape and no other.
object
Example
{ "error": "this token does not have licenses:write"}