Errors & retries
Every non-2xx response is JSON with error (machine
code) and message (human text). Rate-limited responses
carry a Retry-After header. The SDKs retry
automatically on 429 and 5xx; POST and PATCH are never
auto-retried by default so writes don't duplicate.
HTTP status codes
| Status | Error class | Meaning |
|---|---|---|
| 400 | InvalidRequestError | Malformed parameter |
| 401 | AuthenticationError | Missing or invalid API key |
| 403 | ForbiddenError | Feature not available for your tier |
| 404 | NotFoundError | Country, law, or webhook not found |
| 422 | ValidationError | Body failed schema validation |
| 429 | RateLimitError | Monthly quota exceeded; Retry-After set |
| 503 | ServiceUnavailableError | Transient overload |
| 5xx | ServerError | Bug on our side; please retry |
Handling them in the SDK
Retry semantics
Every SDK retries on 429 and 5xx with
exponential backoff + full jitter, honors Retry-After
(both integer-seconds and HTTP-date forms), and caps the total
attempts at max_retries (default 3).
POST and PATCH are not retried by default. A failed
webhooks.create that quietly retried on a 500 could
leave two webhook endpoints behind. If you've verified that a
specific POST is idempotent, opt in per-policy:
Rolling your own
If you can't use the SDK: retry only 429/5xx,
delay = min(2^n + random(), 60), cap at 4 attempts,
stop on any 4xx other than 429, and never retry POST/PATCH unless
the endpoint is documented as idempotent.