Skip to content

The online check an installed application makes

POST
/api/public/license/{checkId}/check
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.

checkId
required
string

The product’s check id. Public — it is in the URL every installed application calls.

Media typeapplication/json
object
license
required

The complete signed licence string.

string
fingerprint

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.

string
nonce

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.

string
>= 16 characters <= 128 characters

The verdict. Null fields are omitted, so a perpetual licence has no expiresAt key at all.

Media typeapplication/json

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
status
required
string
Allowed values: ACTIVE GRACE PENDING EXPIRED REVOKED UNKNOWN INVALID
valid
required

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.

boolean
lid
string format: uuid
startsAt
string format: date-time
expiresAt
string format: date-time
graceDays
integer
revoked
boolean
revokedAt
string format: date-time
revokedReason
string
boundAt
string format: date-time
checkedAt
string format: date-time
serverTime
required
string format: date-time
nonce

The nonce you sent

string
receipt

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.

string
Example
{
"status": "ACTIVE"
}

The request is wrong — a bad date, a missing field, a value the product does not declare.

Media typeapplication/json

Every failure in this API has this shape and no other.

object
error
required
string
Example
{
"error": "this token does not have licenses:write"
}

A missing or wrong check token.

Media typeapplication/json

Every failure in this API has this shape and no other.

object
error
required
string
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.

Media typeapplication/json

Every failure in this API has this shape and no other.

object
error
required
string
Example
{
"error": "this token does not have licenses:write"
}

Rate limited, per product and client address.

Media typeapplication/json

Every failure in this API has this shape and no other.

object
error
required
string
Example
{
"error": "this token does not have licenses:write"
}

The product’s key could not be opened.

Media typeapplication/json

Every failure in this API has this shape and no other.

object
error
required
string
Example
{
"error": "this token does not have licenses:write"
}