← Plugin SDK

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 of ACTIVE, INACTIVE, REVOKED, plus any future states.
  • expiresAt — ISO-8601 UTC string, or null for 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 included machineId. true means this machine is in the activation table; false means it would need /activate first.

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
}