> ## Documentation Index
> Fetch the complete documentation index at: https://developers.safarapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Error envelope, HTTP status mapping, and the stable error codes

Every error response uses the same JSON envelope. Branch on `code`, not on the
message — messages are English-only (for your logs) and may be reworded; `code`
is stable and documented.

```json theme={"theme":"github-dark-dimmed"}
{
  "code": "validation.required.field",
  "message": "Field 'rate_pack_id' is required.",
  "request_id": "req_8f3a1c9e2b7d40",
  "details": { "field": "rate_pack_id" }
}
```

| Field        | Notes                                                                  |
| ------------ | ---------------------------------------------------------------------- |
| `code`       | Stable i18n code, form `domain.subdomain.detail`. Branch on this.      |
| `message`    | English, for your logs. Never localized server-side.                   |
| `request_id` | Quote this when contacting support — it correlates with Safariat logs. |
| `details`    | Optional structured context (offending field, expected value).         |

## HTTP status mapping

| Status | Meaning                                                                   |
| ------ | ------------------------------------------------------------------------- |
| `400`  | Malformed request (syntactic validation).                                 |
| `401`  | API key missing, invalid, expired, or incorrect HMAC signature.           |
| `403`  | Authenticated but not authorized (missing scope, non-allowlisted IP).     |
| `404`  | Resource does not exist or is inaccessible for this partner.              |
| `409`  | Same `Idempotency-Key` reused with a different body. No action performed. |
| `422`  | Syntactically correct but a business rule was violated.                   |
| `429`  | Rate limit exceeded for the current key.                                  |
| `500`  | Internal error — Safariat is notified automatically.                      |
| `503`  | Service temporarily unavailable. Retry later.                             |

## Stable error codes

These codes are part of the contract and will not be renamed within `v1`.

| Code                            | Typical status | When                                                                                           |
| ------------------------------- | -------------- | ---------------------------------------------------------------------------------------------- |
| `auth.api_key.missing`          | 401            | No `Authorization` bearer sent.                                                                |
| `auth.api_key.invalid`          | 401            | Unknown, expired, or revoked key.                                                              |
| `auth.signature.invalid`        | 401            | `X-Signature` does not match (production writes).                                              |
| `auth.timestamp.skew`           | 401            | `X-Timestamp` outside the ±5 min window.                                                       |
| `validation.required.field`     | 400            | A required field is missing — see `details.field`.                                             |
| `adventure.not.found`           | 404            | Unknown `adventure_slug`.                                                                      |
| `adventure.capacity.exhausted`  | 422            | No remaining capacity on the requested slot.                                                   |
| `booking.not.cancellable`       | 422            | Booking already cancelled/completed or past its cancellation window.                           |
| `payment.amount.mismatch`       | 422            | `payment_confirmation` amount differs from the quote.                                          |
| `partner.credit.limit.exceeded` | 403            | Partner credit ceiling reached.                                                                |
| `idempotency.key.conflict`      | 409            | `Idempotency-Key` reused with a different body — see [Idempotency](/api-concepts/idempotency). |
| `rate_limit.exceeded`           | 429            | See [Rate limiting](/api-concepts/rate-limiting).                                              |

<Note>
  Unrecognized codes may be added over time (additive, never breaking). Treat an
  unknown `code` as a generic failure of its HTTP status class.
</Note>
