Error Codes
Numeric error codes returned by the License API and how clients should react to each.
Every non-200 response from /api/v1/license/* carries a stable numeric code in the JSON body. Match on the code, not the HTTP status — the HTTP status describes the category, but the code pins down the exact reason and is more durable across protocol revisions.
| Code | Name | HTTP | When | Client response |
|---|---|---|---|---|
| 1700 | LICENSE_API_BAD_SIGNATURE | 401 | Missing header / malformed nonce / HMAC mismatch / replayed nonce | Check client clock + secret; do not retry blindly |
| 1701 | LICENSE_API_STALE_TIMESTAMP | 401 | |now − timestamp| > 300s | Sync client clock; retry with a fresh timestamp + nonce |
| 1702 | LICENSE_API_MALFORMED | 400 | Body failed Zod schema validation | Fix the request; do not retry |
| 1703 | LICENSE_API_NOT_FOUND | 404 | License key unknown or soft-deleted | Treat as permanent failure; surface support link |
| 1704 | LICENSE_API_INACTIVE | 403 | License exists but not in ACTIVE state (and not REVOKED) | Poll /status on a longer interval |
| 1705 | LICENSE_API_LIMIT_REACHED | 409 | Activation cap exceeded on /activate | Direct user to /dashboard/activations to free a slot |
| 1706 | LICENSE_API_RATE_LIMITED | 429 | Per-key or per-IP bucket tripped | Honour Retry-After; back off with jitter |
| 1707 | LICENSE_API_SECRET_NOT_SET | 500 | Server misconfigured (LICENSE_API_SECRET env var missing) | Report to support; not actionable client-side |
| 1708 | LICENSE_API_REVOKED | 403 | License revoked (chargeback / fraud / manual) | Permanent failure; lock feature; show support link |
| 1709 | LICENSE_API_MACHINE_NOT_ACTIVATED | 404 | License OK but this machine has never been activated | Call /activate |
Retry policy
- Retry with backoff:
RATE_LIMITED,STALE_TIMESTAMP(after clock sync),500(transient). - Retry once after a corrective action:
MACHINE_NOT_ACTIVATED(call/activate, then retry the original op). - Do not retry:
BAD_SIGNATURE,MALFORMED,NOT_FOUND,LIMIT_REACHED,INACTIVE,REVOKED,SECRET_NOT_SET. These are either permanent or require user action.
For retried calls, always generate a fresh nonce — re-using the previous nonce will trip the replay check (BAD_SIGNATURE) on the second attempt.
Stability guarantee
Numeric codes are part of the public contract. New codes will be added; existing codes will not be re-purposed.