The Orizn API uses conventional HTTP status codes. Anything in the 2xx range is a success, 4xx means your request was wrong, 5xx means something on our end is unhappy. Every error response, regardless of status code, ships with a structured JSON body so you can branch on the error.code field rather than parsing message strings.
Error shape
All error responses share the same envelope:
{
"error": {
"type": "invalid_request_error",
"code": "invalid_passport",
"message": "Unknown passport code: 'FR'. Did you mean 'FRA'?",
"param": "passport",
"request_id": "req_2NfBz8m9hPq2WK1J",
"doc_url": "https://orizn.app/extension/docs/errors#400"
}
}typeβ broad category. One ofinvalid_request_error,authentication_error,permission_error,rate_limit_error,api_error.codeβ stable, machine-readable identifier of the specific problem. Branch on this in code.messageβ human-readable explanation. Safe to show to end-users when status is 4xx.paramβ for invalid-request errors, the offending field name.request_idβ copy this into any support ticket; lets us pull the exact request from our logs.doc_urlβ deep link to the section of this page documenting the specific error.
400 Bad Request
You sent malformed input. Do not retry; fix the request and try again.
| Code | Meaning | How to handle |
|---|---|---|
invalid_passport | The passport parameter is missing, empty, or not a recognised ISO-3166 alpha-3 code. | Validate against the alpha-3 set client-side. We return a βdid you mean...β suggestion in the message when we can guess. |
invalid_destination | Same as above for destination. | Same as above. |
invalid_purpose | Unknown purpose value. Allowed: tourism | business | transit | study. | Fix and retry. |
invalid_locale | BCP-47 tag not supported for note translation. | Fall back to en; we will translate the note client-side or via your own pipeline. |
malformed_json | POST body could not be parsed. | Check Content-Type + body. Do not retry. |
401 Unauthorized
The request lacks valid authentication. Do not retry with the same credentials.
| Code | Meaning | How to handle |
|---|---|---|
missing_api_key | The Authorization header is absent. | Add the header. See Authentication. |
invalid_api_key | The key does not exist or was revoked. | Generate a new key from the dashboard. |
expired_api_key | The key has reached its TTL (only set for short-lived test keys). | Rotate to a fresh key. |
403 Forbidden
The credentials are valid but you're not allowed to do this. Usually a billing or feature-gate issue.
| Code | Meaning | How to handle |
|---|---|---|
quota_exceeded | Monthly request quota used up. | Upgrade or wait for the quota reset. The next-reset date is in the X-Orizn-Quota-Reset header. |
feature_not_enabled | You called a feature (e.g. webhooks) that's not on your plan. | Upgrade or remove the unsupported call. |
ip_not_allowed | Your account has IP allow-listing enabled and this request came from an unlisted IP. | Add the IP to the allow-list in the dashboard. |
429 Too Many Requests
You've exceeded the rate limit for your plan. Retry after the delay in the Retry-After header (always present on 429).
| Code | Meaning | How to handle |
|---|---|---|
rate_limited | Per-second burst exceeded. | Sleep for Retry-After seconds then retry. Add client-side concurrency limits. |
concurrency_limited | Too many in-flight requests at once on Pro/Enterprise. | Reduce parallelism or upgrade. |
500 Internal Server Error
Something we didn't plan for went wrong on our side. Retry once with backoff; if it reproduces, copy the request_id and email support.
| Code | Meaning | How to handle |
|---|---|---|
internal_error | Generic 500. Already paged us. | Retry with backoff; report if persistent. |
502 Bad Gateway
A transient failure between our edge and the API origin. Always safe to retry.
| Code | Meaning | How to handle |
|---|---|---|
upstream_unreachable | Edge could not reach origin (briefly). | Retry with exponential backoff. |
503 Service Unavailable
We're in scheduled maintenance or have shed load deliberately. Honour Retry-After; do not hammer.
| Code | Meaning | How to handle |
|---|---|---|
service_unavailable | Maintenance or load shedding. | Wait for Retry-After. Subscribe to status.orizn.app for advance notice. |
Retry strategy
A safe baseline: retry on 429 and any 5xx; never retry 4xx other than 429. Use exponential backoff with jitter to avoid stampedes when many clients see the same blip:
// Pseudo-code: retry transient errors with exponential backoff + jitter.
async function withRetry(fn, { attempts = 4 } = {}) {
let lastErr;
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (err) {
lastErr = err;
// Only retry transient errors. 4xx are caller bugs β don't retry.
const status = err.status ?? 0;
if (status !== 429 && status < 500) throw err;
const backoffMs =
Math.min(2000 * 2 ** i, 16000) + Math.random() * 250;
await new Promise((r) => setTimeout(r, backoffMs));
}
}
throw lastErr;
}The official SDKsimplement this for you out of the box, so you only need to write retry logic if you're calling the API directly.