Errors
All errors share one envelope:
{
"error": {
"code": "INVALID_PARAMETER",
"message": "Parameter 'year' must be between 1900 and 2100.",
"details": { "parameter": "year", "received": "1500" },
"requestId": "req_01HX2K3M4N5P6Q7R8S9T"
}
}The requestId is also returned on the X-Request-ID response header — quote it when contacting support.
Canonical codes
| HTTP | Code | When |
|---|---|---|
| 400 | INVALID_PARAMETER | Malformed or out-of-range query/param |
| 400 | INVALID_DATE_RANGE | Range > 5 years or start > end |
| 401 | MISSING_AUTHENTICATION | No Authorization header |
| 401 | INVALID_TOKEN | Token not found or hash mismatch |
| 401 | REVOKED_TOKEN | Token revoked or owner suspended |
| 403 | DOMAIN_NOT_ALLOWED | Origin not in the token's allowlist |
| 403 | IP_NOT_ALLOWED | Client IP not in the token's allowlist |
| 403 | INSUFFICIENT_ROLE | Admin endpoint accessed by a CLIENT |
| 404 | RESOURCE_NOT_FOUND | Entity does not exist |
| 409 | CONFLICT | Duplicate email on registration, etc. |
| 422 | VALIDATION_ERROR | Request body failed schema validation |
| 429 | RATE_LIMIT_EXCEEDED | Quota or burst limit hit |
| 500 | INTERNAL_ERROR | Unexpected — logged with requestId |
| 503 | SERVICE_UNAVAILABLE | Maintenance or mass refresh in progress |
Retrying
429, 500, and 503 are safe to retry with exponential backoff. Honor Retry-After when present. The rest are deterministic — fix the request first.