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

# Errors

> The CLOB API error envelope, the full error-code table with HTTP mappings, inline vs HTTP errors, idempotency, batch caps, and pagination.

## Error envelope

Every non-2xx response shares one shape. All field names are snake\_case, and the
HTTP status equals `status_code`.

```json theme={null}
{
  "correlation_id": "abc-123",
  "code": "NOT_FOUND",
  "message": "Market not found",
  "status_code": 404,
  "timestamp": "2026-06-03T10:15:30.000Z",
  "path": "/v1/markets/0x.../book"
}
```

`correlation_id` comes from the request's correlation id or the
`x-correlation-id` header; it falls back to `"unknown"`. Quote it when reporting
an issue.

## Error codes

| Code                   | HTTP | When                                                     |
| ---------------------- | ---- | -------------------------------------------------------- |
| `AUTH_MISSING`         | 401  | Required credentials absent                              |
| `AUTH_INVALID`         | 401  | Bad JWT, bad key, or bad secret                          |
| `AUTH_REVOKED`         | 401  | API key revoked                                          |
| `FORBIDDEN`            | 403  | Authenticated but not allowed (e.g. missing permission)  |
| `NOT_FOUND`            | 404  | Market / key / chain not found                           |
| `ORDER_NOT_FOUND`      | 404  | `order_hash` not owned by caller or doesn't exist        |
| `MARKET_NOT_ACTIVE`    | 422  | Market is not `OPEN` and the endpoint needs it to be     |
| `MARKET_NOT_CLOB`      | 422  | Market is AMM — use the AMM routes instead               |
| `INSUFFICIENT_BALANCE` | 422  | Collateral or position shortfall                         |
| `ORDER_EXPIRED`        | 422  | Order past its `expiration`                              |
| `ORDER_ALREADY_FILLED` | 422  | Cannot cancel a fully filled order                       |
| `INVALID_SIGNATURE`    | 422  | EIP-712 signature verification failed                    |
| `WALLET_MISMATCH`      | 422  | Order `signer` ≠ authenticated wallet                    |
| `PRICE_OUT_OF_RANGE`   | 422  | `price` outside `[0.01, 1.00]`                           |
| `SIZE_TOO_SMALL`       | 422  | `size` below the minimum                                 |
| `BATCH_SIZE_EXCEEDED`  | 422  | More than 15 orders in one placement                     |
| `IDEMPOTENCY_CONFLICT` | 409  | Same `fs-idempotency-key` replayed with a different body |
| `SERVICE_DEGRADED`     | 503  | Upstream (chain / DB / cache) unhealthy                  |
| `INTERNAL_ERROR`       | 500  | Anything uncaught                                        |

## Inline vs HTTP errors

`POST /v1/orders` splits errors two ways:

* **Request-level** failures (batch size, auth) are **HTTP errors**.
* **Per-order** rejections (wallet mismatch, bad signature, market closed) are
  returned **inline** inside `results[]`:

```json theme={null}
{ "error": { "code": "WALLET_MISMATCH", "message": "..." } }
```

Always iterate `results[]` and check each item. Success items have an
`order_hash`.

## Batch caps

| Endpoint                                       | Max                                     |
| ---------------------------------------------- | --------------------------------------- |
| `POST /v1/orders`                              | 15 orders per request                   |
| `POST /v1/orders/cancel` (by hash)             | 100 hashes per request                  |
| `POST /v1/orders/cancel` (filter / cancel-all) | No fixed cap — all matching open orders |

Exceeding the placement cap returns `BATCH_SIZE_EXCEEDED` (422). A hash list over
100 fails request validation (422).

## Idempotency

Set `fs-idempotency-key: <string>` on `POST /v1/orders`:

* Keyed per `(user, key)`, with the request body hash stored alongside the result.
* **Same key + same body** → returns the cached result with `_idempotent_replayed: true`.
* **Same key + different body** → `IDEMPOTENCY_CONFLICT` (409).
* Honored on order placement only.

## Pagination

All list endpoints (`/v1/markets`, `/v1/orders`, `/v1/fills`, `/v1/positions`,
`/v1/markets/{id}/trades`) share a cursor envelope:

```json theme={null}
{ "data": [], "next_cursor": "...", "has_more": true }
```

* `cursor` — opaque string from the prior response's `next_cursor`. A malformed
  cursor is treated as no cursor.
* `limit` — default `20`, max `100`.

Results are ordered newest first (`created_at` descending).
