Every error has the same body: a human-readable English error and a stable machine-readable code.
json
{ "error": "No such booking.", "code": "not_found" }Branch on code, never on error. The messages are written for a person reading a log and we improve them without notice; the codes are part of the contract. Some codes carry extra fields next to error and code — they are listed in the table.
Error codes#
| Code | Status | Meaning | Extra |
|---|---|---|---|
api_key_missing | 401 | No Authorization: Bearer header | |
api_key_invalid | 401 | Unknown key | |
api_key_revoked | 401 | The key was revoked — stop retrying | |
api_key_expired | 401 | The key expired — stop retrying | |
app_not_enabled | 403 | The API is not open for this organisation — no key or webhook has been created under SettingsAppsFor developers | |
plan_upgrade_required | 403 | The organisation's plan does not include the API | |
site_unavailable | 403 | The organisation is suspended or deleted — every key and webhook is off. Stop retrying until the merchant tells you otherwise | |
insufficient_scope | 403 | The key lacks a scope | required_scope |
not_found | 404 | No such resource — also the answer for another organisation's id | |
site_not_found | 404 | The key authenticated but its organisation could not be read | |
experience_date_not_found | 404 | No such departure when creating a booking | |
validation_failed | 400 / 422 | See below | issues[] |
payload_too_large | 413 | The request body exceeds 64 KB | |
idempotency_key_required | 400 | This endpoint requires an Idempotency-Key | |
idempotency_key_reused | 422 | That key was already used with a different body | |
idempotency_in_progress | 409 | A request with that key is still running | |
insufficient_capacity | 409 | Not enough seats left on the departure | seats_available |
conflict | 409 | The request contradicts the current state | |
webhook_url_invalid | 422 | Not an https URL, contains credentials, or is an IP address in a private range. Host names are checked again at every delivery, so a name that points inward fails there instead | issues[] |
webhook_endpoint_limit | 422 | The organisation already has 10 webhook endpoints | |
webhook_delivery_not_retryable | 409 | That delivery already succeeded, or is queued | |
rate_limited | 429 | Too many requests — see Rate limits | |
internal_error | 500 | Something broke on our side |
Which of these a given endpoint can return is listed per operation in the API reference.
Validation errors#
validation_failed is 400 for unparseable JSON, a bad query parameter or a starting_after cursor that was modified (cursors are signed — pass them back untouched). It is 422 when the body parsed but is not acceptable. Either way it lists what was wrong, field by field:
json
{
"error": "The request body is not valid.",
"code": "validation_failed",
"issues": [
{ "path": "guests.0.count", "message": "Expected number, received string" },
{ "path": "customer.email", "message": "Invalid email" }
]
}What to retry#
| Status | Retry? |
|---|---|
429 | Yes, after retry-after seconds (or the window in x-ratelimit-reset) |
5xx | Yes, with backoff — and the same Idempotency-Key |
409 idempotency_in_progress | Yes, after a moment, same key |
Other 4xx | No. Fix the request first |
401 api_key_revoked, 401 api_key_expired and 403 site_unavailable in particular will not fix themselves — stop and alert a person. See Idempotency for why a retry with the same key is always safe.
Getting help#
When you contact Awrora support about an error, bring the code from the response, roughly when the request was made, and the key's prefix (the first twelve characters shown in Awrora). Never send the whole key. Every authenticated call is logged with its path, status and duration, so the request can usually be found quickly. 429 responses are sampled — at most one log row per key per minute.