Cessio Docs
Guides

Error handling

The stable error contract and what your bot should do for each case

Error bodies are {error, code?}. Match on the HTTP status and the machine-readable code; the error string is for logs and humans — its wording may change without notice.

The matrix

HTTPcodeMeaningBot action
400—invalid body or query (zod validation text in error) — e.g. an RFQ naming an unknown instrument or an unreachable makerfix the request, don't retry as-is
400BELOW_MIN_NOTIONALPOST /rfq: the ticket is under the desk minimum (GET /config → minNotionalUsd)raise the quantity
401—unknown API keyfix config, don't retry
403—not invited to the RFQ / not your quote / not your RFQdrop, don't retry
404—RFQ, quote, transfer or action not found (closed, expired) · a withdrawal of an unknown instrumentdrop, don't retry
409RETRY_LATERtransient precondition: a quote's allocations still landing, a withdrawal executingretry with backoff
409INSUFFICIENT_FUNDSyour free holdings cannot cover it (a quote's allocation, your leg of an accept, a withdrawal); nothing was recordedtop up, then retry
409DUST_TRADEa leg (typically the fee) rounds to zero at 10 decimalsdon't quote this ticket
409(none)deadline passed · the quote is settling or no longer available · an explicit validUntil in the past or past the deadline · a settlement already in flight on the RFQ · contract contention · on POST /tx/execute, an action whose contract is spent or whose trade no longer settles (it leaves the queue)read error, usually drop
410—an action or a registration expired before you signedstart that step over
429—per-IP limit on /maker/register/start or /maker/challengeback off
501—a withdrawal on the local sandbox (no token-standard registry there) · a faucet draw where no faucet runs—
502—the ledger rejected the commandread error; retry only after changing something
503— / RETRY_LATERledger unavailable / busy / auth hiccup, or a write the desk could not persistretry with backoff

Batch execute: partial failure and retries

A signatures batch on POST /tx/execute answers 200 even when entries fail — check each entry's status. A failed entry carries retryable: true is transient (ledger unavailable or busy — retry that entry with backoff), false is terminal for that entry (unknown, expired, contract gone). The error text is for logs, as everywhere.

The reliable recovery after a failed or timed-out execute is GET /tx/pending: an action still listed wants its signature again; an action absent from the list will not run again — it executed, or its flow died first (it expired, or was cancelled with its quote or trade). A blind resend of the whole batch would instead report error for every entry that already succeeded.

WebSocket errors

The stream closes with 4401 on a missing or unknown X-API-Key — and mid-stream when the key it opened with is rotated. Any other close is operational — reconnect with backoff; the snapshot restores your state (see Subscribe to RFQs).

Practical notes

  • A 409 on POST /maker/quotes after the RFQ deadline is normal racing — RFQ deadlines are short by design. Drop the RFQ and move on.
  • trade.failed on the stream is not an HTTP error but ends the trade the same way: nothing moved, the accepted quote is revoked, and the RFQ stays open for another accept until its deadline.
  • Malformed frames on the stream should be ignored, not fatal — parse defensively.

On this page