# Errors

Every error response shares one envelope shape, and every status code maps to a specific, predictable condition. This page is the reference for both.

## Error envelope

All error responses return the same JSON object:

```json
{
  "code": "BOOKING_NOT_CANCELLABLE",
  "message": "booking is not cancellable",
  "details": null
}
```

| Field     | Type           | Notes                                                                        |
| --------- | -------------- | ---------------------------------------------------------------------------- |
| `code`    | string         | A stable, machine-readable error code. Branch on this, not on `message`.     |
| `message` | string         | A human-readable description. Wording may change; do not parse it.           |
| `details` | object \| null | Optional structured context for the error. Absent or `null` for most errors. |

Authentication failures from the middleware use the same `code` / `message` shape (for example `{ "code": "auth.invalid_bearer", "message": "..." }`).

## Status-code reference

| Status                      | Meaning                                                                                                                                                                                                                                                        | How to react                                                                                                                          |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`           | The request is malformed — bad JSON, an invalid date, a failed field validator, or (on prebook/book) a missing `Idempotency-Key` (`IDEMPOTENCY_KEY_REQUIRED`).                                                                                                 | Fix the request. Do not retry unchanged.                                                                                              |
| `401 Unauthorized`          | The bearer token is missing, malformed, expired, or signature-invalid. Codes: `auth.missing_bearer`, `auth.invalid_bearer`. Carries a `WWW-Authenticate: Bearer` challenge.                                                                                    | Obtain a fresh token (see [Authentication](/developer/authentication.md)) and retry.                                                  |
| `403 Forbidden`             | The token is valid but lacks the scope the endpoint requires. Code: `auth.insufficient_scope`.                                                                                                                                                                 | Use a credential/token that carries the required scope. Do not retry with the same token.                                             |
| `404 Not Found`             | The addressed resource does not exist under your tenant (unknown property or booking `public_id`).                                                                                                                                                             | Verify the `public_id`. Do not retry blindly.                                                                                         |
| `409 Conflict`              | The request conflicts with current state — an `Idempotency-Key` reused with a different body (`IDEMPOTENCY_KEY_CONFLICT`), an expired prebook token (`PREBOOK_EXPIRED`), or a booking that is non-cancellable / past its deadline (`BOOKING_NOT_CANCELLABLE`). | Resolve the conflict: use a new key for a new operation, re-prebook if the token expired, or stop if the booking cannot be cancelled. |
| `422 Unprocessable Entity`  | The request is well-formed but cannot be fulfilled (for example an unsupported currency-conversion pair).                                                                                                                                                      | The request will not succeed as-is; adjust the inputs (e.g. request a supported currency).                                            |
| `500 Internal Server Error` | An unexpected server-side error.                                                                                                                                                                                                                               | Retry with backoff. If it persists, capture the `trace_id` from the response and contact support.                                     |

## Reacting safely

* **Branch on `code`, never on `message`.** Codes are stable; messages are not.
* **Retry only the retryable.** `500` is safe to retry with backoff. `401` is retryable after refreshing the token. `400`, `403`, `404`, `409`, and `422` indicate a request or state problem and will not be fixed by an unchanged retry.
* **Retry writes with the same idempotency key.** When retrying `prebook` or `book`, re-send the **same** `Idempotency-Key` and identical body so the retry replays rather than duplicates — see [Idempotency](/developer/idempotency.md).
* **Keep the `trace_id`.** Success and many error responses carry a `trace_id`; log it so a single request can be traced end to end in a support enquiry.

### Search is resilient to per-property failure

`POST /search` returns `200` even when an individual property fails: the failure surfaces inline on `results[i].error_code` (`PROPERTY_NOT_FOUND`, `UNSUPPORTED_FX_PAIR`, `INTERNAL_ERROR`) rather than failing the whole batch. A top-level `422` is returned only when **every** property failed with an unsupported currency pair. Inspect each `results[i].error_code` and treat a populated value as that property's error.

## Next steps

* [Authentication](/developer/authentication.md) — resolving `401` and `403`.
* [Idempotency](/developer/idempotency.md) — resolving `409` on writes.
* [The booking flow](/developer/booking-flow.md) — the endpoints these codes apply to.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://adrasis.gitbook.io/developer/errors.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
