The online check an installed application makes
const url = 'https://app.dycrypt.com/o/acme/api/public/license/example/check';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"license":"example","fingerprint":"DYC1.a1b2c3d4.e5f6a7b8.00000000.c9d0e1f2.a3b4c5d6.9f2c","nonce":"example"}'};
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/public/license/example/check \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "license": "example", "fingerprint": "DYC1.a1b2c3d4.e5f6a7b8.00000000.c9d0e1f2.a3b4c5d6.9f2c", "nonce": "example" }'Answered by dycrypt-licence, a separate service that holds no key
material, so installed software keeps getting answers while the console is
down.
Possession of a correctly signed licence is the credential for the licence itself: the signature is verified before anything is looked up, so licence ids cannot be enumerated.
Prefer an SDK. It generates the nonce, sends the fingerprint, and verifies the receipt — and an integration that skips that last step enforces nothing.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The product’s check id. Public — it is in the URL every installed application calls.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The complete signed licence string.
Optional — an older SDK does not send one, and a licence that binds nothing does not need it. Sending it is what lets a licence bind to one machine.
Generate a fresh one for every request. It comes back inside the signature, which is what stops a captured answer from being replayed. 16–128 URL-safe characters.
Responses
Section titled “Responses”The verdict. Null fields are omitted, so a perpetual licence has no
expiresAt key at all.
Null fields are omitted rather than sent as null. INVALID means the
signature did not verify and arrives with nothing else attached; UNKNOWN
means the signature is good but this issuer has no record of that lid.
object
True only for ACTIVE and GRACE. A renewed licence answers
valid: false with status: "ACTIVE" — a new string exists and the one
you presented is not it.
The nonce you sent
What makes the answer trustworthy. A signature by the product’s own key — the same key that signed the licence, so your application already holds the public half and needs nothing new.
It covers, in order, separated by the ASCII unit separator 0x1F:
DYCR1 · lid · status · nonce · checkedAt · boundAt · fpDigest
fpDigest is the first 32 hexadecimal characters of SHA-256 over the
fingerprint string you sent, which is what keeps a receipt from being
carried to another machine. Absent fields are empty, never the word
null.
An answer whose receipt does not verify is not an answer: do not
record it as a successful check, do not cache it, and let the licence
continue toward STALE.
Without this, whoever controls a machine points your issuer hostname at
a stub answering ACTIVE forever — one line in the hosts file. TLS does
not help; the trust store is theirs too. A stub cannot sign, so blocking
the check is all that is left, and a blocked check ends in STALE.
Example
{ "status": "ACTIVE"}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"}A missing or wrong check token.
Every failure in this API has this shape and no other.
object
Example
{ "error": "this token does not have licenses:write"}Online checking is disabled on this deployment, or the slug is unknown. The SDKs read this as “no answer” and keep the offline verdict.
Every failure in this API has this shape and no other.
object
Example
{ "error": "this token does not have licenses:write"}Rate limited, per product and client address.
Every failure in this API has this shape and no other.
object
Example
{ "error": "this token does not have licenses:write"}The product’s key could not be opened.
Every failure in this API has this shape and no other.
object
Example
{ "error": "this token does not have licenses:write"}