Error envelope
Every non-2xx response shares one shape. All field names are snake_case, and the HTTP status equalsstatus_code.
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[]:
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 |
BATCH_SIZE_EXCEEDED (422). A hash list over
100 fails request validation (422).
Idempotency
Setfs-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:
cursor— opaque string from the prior response’snext_cursor. A malformed cursor is treated as no cursor.limit— default20, max100.
created_at descending).