> For the complete documentation index, see [llms.txt](https://docs.strikelabs.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.strikelabs.app/api-reference/errors.md).

# Errors

The real shapes and status codes the venue returns today, not an idealised taxonomy. There are two failure shapes and it matters that you can tell them apart.

## Shape 1 — the error envelope

Every non-2xx JSON body except an order rejection is exactly this:

```json
{ "error": "seriesId required" }
```

One human-readable string. There is **no error code, no field path, and no nested detail** — do not build a parser expecting them. **Branch on the HTTP status** and log the message; the strings are stable enough to log but are not an enum to switch on.

## Shape 2 — a rejected order

An order the engine refuses is **not** an error envelope. It comes back `400` carrying the normal order shape:

```json
{
  "status": "rejected",
  "reason": "insufficient buying power (need ~3126.25, have 500.00)",
  "fills": [],
  "orderId": 0,
  "account": { ... }
}
```

The field is `reason` — not `error`, not `reject`. `restedQty` is **absent** on a rejection, and `orderId` is always `0`.

{% hint style="info" %}
**How to distinguish them**

Both are `400` on `POST /v1/order`. Test for the presence of `status`: if it is there, the request was well-formed and the engine declined it; if instead you have `error`, the request itself was malformed.
{% endhint %}

## Order statuses

| STATUS      | HTTP | MEANING                                                                                                           |
| ----------- | ---- | ----------------------------------------------------------------------------------------------------------------- |
| `filled`    | 200  | Fully traded. Nothing rested.                                                                                     |
| `partial`   | 200  | Some traded; the remainder is resting.                                                                            |
| `rested`    | 200  | Nothing traded; it is on the book. Note the spelling — `rested`, not `resting`.                                   |
| `cancelled` | 200  | Nothing traded and nothing rested — e.g. a market order that found no liquidity. **This is a 200**, not an error. |
| `rejected`  | 400  | The engine declined it. See `reason`.                                                                             |

## Every reject reason

The complete set. Values in parentheses are interpolated to two decimal places.

| REASON                                            | WHAT TO DO                                                                                                                 |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `unknown series`                                  | The `seriesId` is not listed. Re-read `/v1/series`; it may have expired or settled.                                        |
| `series settled`                                  | Already settled. Nothing to trade.                                                                                         |
| `series expired`                                  | Past its 20:00 ET cutoff. Trading stopped exactly at the cutoff.                                                           |
| `bad qty`                                         | Non-positive, or not representable.                                                                                        |
| `bad price`                                       | Non-positive limit price, or not representable.                                                                            |
| `no liquidity`                                    | A market order found nothing to cross. Rest a limit order instead.                                                         |
| `insufficient buying power (need ~N, have M)`     | Cash minus what your resting orders and shorts already reserve is not enough. Cancel orders or add funds.                  |
| `insufficient margin for short (need ~N, have M)` | Opening or extending the short needs more than your buying power. See [the margin formula](/protocol/market-structure.md). |
| `insufficient cash`                               | Seen when meeting a margin call: cash does not cover the buy-back plus its fee.                                            |
| `account equity depleted`                         | Equity is at or below zero. Nothing can be opened.                                                                         |
| `margin call — reduce-only (buy back shorts)`     | `equity < maintenanceMargin`. Only a buy reducing an existing short is accepted.                                           |
| `margin is off — enable margin to sell short`     | Cash account. `POST /v1/margin` with `enabled: true` first.                                                                |
| `account frozen — no linked wallet address`       | The account has no proven owner. Sign in with the wallet; if it persists, it needs operator reconciliation.                |
| `house line exceeded (need ~N, headroom M)`       | The market maker's own exposure limit. Not about your account — try a smaller size or wait.                                |

The em-dashes in those strings are real U+2014 characters, not hyphens. Match on substrings if you must match at all.

## Status codes

| CODE    | WHEN                                                                                             | RETRY?                       |
| ------- | ------------------------------------------------------------------------------------------------ | ---------------------------- |
| **200** | Success. Includes `cancelled` orders and `ok: false` cancels — neither is an error.              | —                            |
| **204** | `OPTIONS` preflight.                                                                             | —                            |
| **400** | Malformed request, a missing field, an unrepresentable number — or a rejected order.             | No. Fix the request.         |
| **401** | Missing/unknown token, a signing fault, or an unsigned write while signatures are mandatory.     | Only after fixing the cause. |
| **403** | Wrong credential for an operator or maker route. Also a revoke for a key that is not yours.      | No.                          |
| **404** | Unknown series, unknown withdrawal id — or **a route that does not exist in this funding mode**. | No.                          |
| **409** | A maker mutation attempted outside a fenced quote session, or a deposit conflict.                | No.                          |
| **413** | Body over the route's limit.                                                                     | No.                          |
| **429** | **Replay-memory backpressure only.** See below.                                                  | **Yes.**                     |
| **500** | An internal fault. Should not happen; report it.                                                 | With backoff.                |

{% hint style="warning" %}
**`404` can mean "wrong funding mode"**

`/v1/withdraw` and `/v1/reserves` are routed **only** in `deposits` mode. In `paper` mode they answer `404 {"error": "not found"}` — the same as a typo'd URL. Check `/healthz` before concluding you have the path wrong.

Their absence is deliberately not leaked as a `403`, so the 404 is the same with or without a credential.
{% endhint %}

## Signing errors

All `401` except the last, and all reading alike on the wire — which is why you should surface the venue's message verbatim rather than rewording it.

| MESSAGE                                                   | CODE    | CAUSE                                                                                                             |
| --------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| `bad signature`                                           | 401     | The signature did not recover to the session key. A code or envelope bug.                                         |
| `unknown or revoked session key`                          | 401     | Never approved, revoked, or swept after long expiry. Approve a new one.                                           |
| `session expired — approve a new one`                     | 401     | Past its `expiresAt`.                                                                                             |
| `nonce outside the accepted window`                       | 401     | **A clock problem.** More than 60 s from venue time, in either direction.                                         |
| `nonce already used`                                      | 401     | Replay. Step the nonce forward per request.                                                                       |
| `approval was not signed by the account it names`         | 401     | The approval recovered to someone other than `address`.                                                           |
| `expiry must be in the future and within 30 days`         | 401     | Bad `expiresAt` on an approval.                                                                                   |
| `field contains a newline`                                | 401     | A field carried `\n` or `\r` and could have forged a different envelope.                                          |
| `this request must be signed — approve a trading session` | 401     | You sent only a bearer token while signatures are mandatory.                                                      |
| `nonce and signature required with sessionKey`            | 400     | `sessionKey` present but the other two missing — or `nonce` sent as a string or float. It must be a JSON integer. |
| `too many orders in flight — retry`                       | **429** | Backpressure. **Retry.** Not a credential problem — do not re-approve.                                            |

{% hint style="info" %}
**A bad signature does not burn the nonce**

Deliberately: otherwise anyone who could see your nonces could lock you out by spending each one with garbage before your real order landed. Retrying the same nonce with a correct signature works.
{% endhint %}

## The 429 is not a rate limit

The venue returns exactly one `429`, and it is **overload backpressure**: a session key spent more nonces inside the freshness window than the venue will remember. Refusing is the safe answer — forgetting a live nonce to make room would make that signature replayable — and it costs you a retry.

**No `Retry-After` header is set.** Back off briefly and retry; a client hitting this is signing faster than roughly a million requests per minute from one key. Do not treat it as a rate limit and do not treat it as a reason to re-approve.

## Rate limits

Enforced at the edge, in front of the venue, per IP. These are the published numbers and are therefore a contract:

| ROUTES                                    | LIMIT                                                                |
| ----------------------------------------- | -------------------------------------------------------------------- |
| `/v1/order`, `/v1/cancel`, `/v1/withdraw` | 60 requests / minute                                                 |
| `/v1/auth/*`                              | 10 requests / minute — signature grinding is the thing being limited |
| Everything else under `/v1`               | 300 requests / minute                                                |
| `/ws`                                     | 10 new connections / minute                                          |

`GET /v1/reserves` is deliberately generously limited. It is the number a counterparty checks when they are already nervous, and throttling it during an incident would read as hiding.

## Body size limits

| ROUTES                                                | LIMIT                 | OVER                                      |
| ----------------------------------------------------- | --------------------- | ----------------------------------------- |
| `/v1/withdraw` and the operator money routes          | 4 KiB                 | `413 {"error": "request body too large"}` |
| `/v1/order`, `/v1/cancel`, `/v1/margin`, `/v1/auth/*` | Not currently bounded | —                                         |

Stated accurately rather than reassuringly: the trade routes have no size cap today. Do not read that as licence to send a large body — it is a limit that may be added, and a well-formed order is a few hundred bytes.

## CORS

Every response carries `Access-Control-Allow-Origin: *`, with `content-type`, `x-paper-token` and `authorization` among the allowed headers, and `GET, POST, OPTIONS` allowed. Preflight answers `204`. Credentials are not allowed, so a browser cannot send cookies — the bearer token is the only credential and it goes in a header.

## Retry guidance

* **Retry:** `429`, `500`, and transport failures — with backoff, and with a **fresh nonce**.
* **Do not retry:** `400`, `401`, `403`, `404`, `409`, `413`. Nothing about them changes on a second attempt.
* **Never retry a write blindly.** Reusing the same nonce is refused as a replay, which is the venue protecting you; minting a new one turns an ambiguous timeout into a possible *second* order. On a timeout, read `GET /v1/me` or `/v1/fills` and find out what happened before acting.

***

Error strings are quoted verbatim from the venue's source. Rate limits are configured at the edge, in front of the venue.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.strikelabs.app/api-reference/errors.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
