Skip to main content

Error Codes

TL;DREvery error response is a small JSON envelope, { code, message }, with a mapped HTTP status. code is a stable numeric error code you can branch on; message is the human-readable reason. Every response (success and error) carries an x-request-id header for correlating with server logs. Success responses are not enveloped; their typed body is returned directly.

Error shape

A failed REST request returns a non-2xx HTTP status and the envelope:
A failed /v1/stream order frame returns an error reply carrying the same numeric code and message the REST path would have returned:
Every response includes an x-request-id header:
Quote it when reporting an issue; it ties your request to the server’s log line.

Code catalogue

Codes are grouped by class. The HTTP status is derived from the class. Codes are stable: branch on the number, not the message text (which may change).

Status reference

Conditions by endpoint

Authentication

  • 401: bad credentials (POST /auth/token); a missing, expired, or revoked token on an authenticated request; or a token an operator invalidated. Token expiry is exact — there is no grace period past expires_in.
  • 403 (1150): the account is suspended. Returned both on authenticated requests and on POST /auth/token, so re-authenticating does not clear it. Not retryable.
  • 429 (1401): this account’s authentication allowance is exhausted. An unrecognised api_key is refused before any verification work, so it consumes no allowance.
  • 503 (1402): verification is at capacity; requests are refused rather than queued. Retry after a short, jittered delay.
Authenticate once per token lifetime, not once per action — a client that caches its token for the expires_in window will not meet these limits.

Place order

  • 400: malformed fields, a failed field-element check, a zero order id, a bid with zero price, an off-tick non-zero price, an opening that does not match the signed commitment, or collateral below the required (nominal + fee) floor.
  • 400 (1010 / 1011): the collateral proof was rejected at intake — either its Merkle root has aged out of the recent-root window, or the proof itself did not verify. Rebuild against a current root and resubmit.
  • 403: the trading-key signature does not verify.
  • 409: the order_id is already in the book, or the collateral commitment is reserved by another live/pending order.

Cancel / modify

  • 403: signature does not verify, or the key does not own the order.
  • 404: the order is not resting (filled / expired / cancelled).
  • 409: cancel nonce or boot session is stale.
  • 409 (modify): the replacement order_id is already booked.

Reads (orders, settlement, tree)

  • 400: malformed id / parameter hex.
  • 404: unknown order / batch / note. GET /orders/{id} intentionally returns this same response for a foreign account’s order.
  • 503 (5002, tree only): the mirror disagrees with Solana. Read the selected MerkleTree account and leaves from chain; do not keep retrying the unsafe mirror.
A rejected order is better than an accepted one that cannot settleCollateral proofs are verified when the order is submitted, not when it settles. An order whose proof is stale or invalid is refused immediately with 1010 / 1011 and costs you nothing. Rebuild the proof against a current root and resubmit.

Handling errors

Make cancels idempotent in your logicA cancel that races a fill returns 404 once the order has matched. Treat 404-on-cancel as success-equivalent (“the order is gone”) and reconcile state, rather than as a hard error.