Errors
One error shape, a fixed list of codes, and nothing leaked from inside the system.
Error shape
json
{
"error": {
"code": "INVALID_SUBDIVISION",
"message": "subdivision_code 'XX' is not supported for country MY.",
"request_id": "req_9f2c41a7be03d5710c8e2b44"
}
}Branch on code, never on message. Messages are written for humans and may be reworded. Some errors add context fields such as limit, used or retry_after_seconds.
What errors never contain
No stack traces, no SQL, no provider internals, no configuration values. If something breaks on our side you get 500 INTERNAL_ERROR and a request_id to quote.
Code reference
| Code | HTTP | Meaning and fix |
|---|---|---|
| INVALID_REQUEST | 400 | The request was not a POST, or mixed mutually exclusive fields. |
| INVALID_DATE | 400 | A date field was missing, malformed, or not a real calendar date. |
| INVALID_JSON | 400 | The request body was not a JSON object. |
| PAYLOAD_TOO_LARGE | 413 | The request body exceeded 64 KB. |
| UNKNOWN_FIELD | 400 | The body contained a field the operation does not accept. |
| MISSING_API_KEY | 401 | No Authorization: Bearer key and no x-api-key header. |
| INVALID_API_KEY | 401 | The key does not match any active key. |
| REVOKED_API_KEY | 401 | The key was revoked. |
| EXPIRED_API_KEY | 401 | The key passed its expiry date. |
| API_KEY_IN_QUERY_STRING | 401 | An api_key query parameter was present. Keys must travel in headers only. |
| ENVIRONMENT_MISMATCH | 403 | A test key was used against live, or the reverse. |
| FEATURE_NOT_AVAILABLE | 403 | The account does not have this feature. |
| PLAN_UPGRADE_REQUIRED | 403 | The operation needs a higher plan. |
| NOT_FOUND | 404 | Unknown operation path. |
| BUSINESS_CALENDAR_NOT_FOUND | 404 | No Business Calendar with that id is owned by this account. |
| BUSINESS_CALENDAR_FORBIDDEN | 403 | The calendar exists but is not usable by this account. |
| CONFLICT | 409 | The request conflicts with existing state. |
| INVALID_COUNTRY | 422 | country_code is not a supported ISO 3166-1 country. |
| INVALID_SUBDIVISION | 422 | subdivision_code is not supported for that country. There is no fallback to national holidays. |
| INVALID_TIMEZONE | 422 | timezone is not a valid IANA identifier. |
| RANGE_TOO_LARGE | 422 | The date range exceeded the maximum supported span. |
| VALIDATION_ERROR | 422 | A field failed its type, range or format rule. |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests this minute for the account's plan. |
| API_QUOTA_EXCEEDED | 429 | The account's monthly request allowance is used up. |
| INTERNAL_ERROR | 500 | Something failed on our side. Quote the request_id. |
| SERVICE_UNAVAILABLE | 503 | The API is not accepting traffic, or usage could not be recorded. |
Retry policy
429: retry after theretry-afterheader. Back off exponentially; do not hammer.503: retry with backoff, the condition is temporary.4xxother than 429: do not retry. Fix the request or the key first.500: retry once, then alert with therequest_id.