# Errors

> The error envelope, every error code the API returns, and which errors are worth retrying.



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 <Path>Settings → Apps → For developers</Path>                                               |                   |
| `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](/developers/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](/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 — &#x2A;*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](/developers/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). &#x2A;*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.
