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

# Error handling

> HTTP status codes, response shapes, and client integration patterns.

The PolyOrderbooks API uses conventional HTTP status codes. Error bodies fall into two shapes depending on the layer that rejected the request.

## Response shapes

### Gateway auth (`401`)

Authentication and rate-limit responses use a single `detail` field:

```json theme={null}
{
  "detail": "Authentication required."
}
```

```json theme={null}
{
  "detail": "Invalid API key."
}
```

### Application errors (`400`, `403`, `404`)

Business logic and validation use `error` + `message`:

```json theme={null}
{
  "error": "bad_request",
  "message": "start_ts is required"
}
```

```json theme={null}
{
  "error": "forbidden",
  "message": "Resolution '1s' is not available on your starter plan. Finest allowed: 60s."
}
```

### Rate limits (`429`)

```json theme={null}
{
  "detail": "Rate limit exceeded. Please try again later."
}
```

Includes `Retry-After` header (seconds). See [Rate limits](/rate-limits).

## Status code reference

| Code  | Meaning                  | Typical body        | Action                              |
| ----- | ------------------------ | ------------------- | ----------------------------------- |
| `400` | Invalid parameters       | `error` + `message` | Fix request; do not retry unchanged |
| `401` | Missing/invalid API key  | `detail`            | Check `X-API-Key` header            |
| `403` | Plan limit or permission | `error` + `message` | Upgrade plan or adjust query        |
| `404` | Resource not found       | `error` + `message` | Verify slug, token id, or filters   |
| `429` | Rate limit exceeded      | `detail`            | Wait for `Retry-After`, then retry  |
| `500` | Server error             | varies              | Retry with exponential backoff      |

## Common validation errors

<Tabs>
  <Tab title="Missing parameters">
    ```json theme={null}
    {
      "error": "bad_request",
      "message": "start_ts is required"
    }
    ```
  </Tab>

  <Tab title="Invalid time window">
    ```json theme={null}
    {
      "error": "bad_request",
      "message": "end_ts must be after start_ts"
    }
    ```
  </Tab>

  <Tab title="Unsupported resolution">
    ```json theme={null}
    {
      "error": "bad_request",
      "message": "Unsupported resolution '2m'. Allowed: 10m, 15m, 1d, 1h, 1m, 1s, 5m, 60s, 6h"
    }
    ```
  </Tab>

  <Tab title="Plan resolution">
    ```json theme={null}
    {
      "error": "forbidden",
      "message": "Resolution '1s' is not available on your starter plan. Finest allowed: 60s."
    }
    ```
  </Tab>

  <Tab title="Not found">
    ```json theme={null}
    {
      "error": "not_found",
      "message": "Market not found: unknown-slug"
    }
    ```
  </Tab>
</Tabs>

## Integration pattern

```python theme={null}
import requests

response = requests.get(url, params=params, headers=headers, timeout=60)

if response.status_code == 429:
    retry_after = int(response.headers.get("Retry-After", 60))
    # time.sleep(retry_after) and retry — see rate-limits.mdx

if not response.ok:
    try:
        payload = response.json()
        msg = payload.get("message") or payload.get("detail") or response.text
    except Exception:
        msg = response.text
    raise RuntimeError(f"API error {response.status_code}: {msg}")

payload = response.json()
```

<Tip>
  Log HTTP status, request path, and the parsed error string. Include your client request id when contacting [contact@polyorderbooks.com](mailto:contact@polyorderbooks.com).
</Tip>

## Idempotency

`GET` requests are safe to retry on transient network failures and `5xx` responses. Do not retry `400`, `403`, or `404` without changing the request.
