POST /api/v1/license/status
Read-only license health check. Use it at plugin startup before rendering any UI.
POST /api/v1/license/status
A read-only check the plugin can call at startup to know whether the cached license key is still valid before rendering any UI. Idempotent. Cheap. Always prefer this over /heartbeat when all you need is "is this key still good".
Request
Headers: see HMAC Signing.
Body (JSON):
{
"licenseKey": "uuid-v4", // required
"machineId": "8-128 chars" // optional; include to also get machineActivated
}When machineId is supplied, the response includes a machineActivated flag. When omitted, the field is absent — the response is a pure license-level check.
Responses
200 OK
{
"ok": true,
"status": "ACTIVE",
"expiresAt": null,
"product": { "slug": "procgenerator", "name": "Procedural Generator" },
"machineActivated": true
}status— one ofACTIVE,INACTIVE,REVOKED, plus any future states.expiresAt— ISO-8601 UTC string, ornullfor perpetual licenses.product— the product this license unlocks. Useful for cross-product plugins that want to render product-specific UI.machineActivated— present only when the request includedmachineId.truemeans this machine is in the activation table;falsemeans it would need/activatefirst.
401 LICENSE_API_BAD_SIGNATURE (1700) / STALE_TIMESTAMP (1701)
Signature verification failed.
404 LICENSE_API_NOT_FOUND (1703)
License key unknown or soft-deleted.
429 LICENSE_API_RATE_LIMITED (1706)
Honour the Retry-After header.
Caching
The plugin may cache a 200 OK { status: "ACTIVE" } response for up to 10 minutes before re-checking. Caching for longer means the user has to wait for the cache to expire after a refund / revocation before the plugin disables itself. Caching for shorter means the API gets hammered on plugin start-up.
For headless build farms that spawn many short-lived Editor processes, hit /status once at boot and pass the cached result to every process via an environment variable or shared file. The plugin reads the cached result and only re-validates if it is older than 10 minutes.
Usage pattern
async function licenseHealthAtStartup(licenseKey: string, machineId: string) {
const resp = await postSigned("/api/v1/license/status", { licenseKey, machineId });
if (resp.status === 200) {
const body = await resp.json();
if (body.status === "ACTIVE" && body.machineActivated) return "ok";
if (body.status === "ACTIVE" && body.machineActivated === false) return "activate-needed";
return "blocked";
}
if (resp.status === 404) return "blocked"; // unknown / deleted
if (resp.status === 429) return "retry-later"; // rate limited
return "transient-error"; // 4xx or 5xx — fall back to cached state if any
}