status repeats the HTTP status. Switch on error.code — it is always
present. The other fields are optional:
trace_id— 32-hex trace id, the same value as theX-Trace-Idresponse header. Quote it in support tickets.retryAfterSec— on rate-limit and back-pressure rejects; also sent as theRetry-Afterheader.retryable— whether sending the same request again as-is can succeed. Absent means the server makes no claim.details— endpoint-specific structured context.
5xx response never carries raw server error text: message is a
generic sentence (or, for a few codes, a fixed explanation of what to do
next), and details is omitted except for details.clientOrderId on
some order-placement errors.
HTTP status code conventions
Business rejects vs HTTP errors
Every non-2xx response uses the error envelope above. A few2xx
responses also report a business outcome in the body: order placement
(201, status: "REJECTED" + code), each entry of place-batch
(success: false + code), a withdrawal request (201,
status: "rejected" + code for a compliance refusal, or
status: "REJECTED" with an empty id and the reason in reason, for
example insufficient balance) and a single cancel (200,
status: "not_found" / "already_terminal", or 202,
status: "cancel_pending" for a cancel that is recorded and not complete
yet, which you send again after Retry-After). Branch on the HTTP
status first: on a 2xx, read the body’s status; on anything else,
read error.code.
Order placement — full success-envelope shape with status: 'REJECTED'
POST /api/orders/place returns the same JSON shape for an accepted
order and for a business reject — they share the schema and are
distinguished by the top-level status field. (Request errors such as
400 invalid_request or 401 maker_mismatch use the standard error
envelope instead.) The HTTP status is
201 Created even on reject because the request was accepted and
processed; the body tells you the matcher’s verdict.
body.status: REJECTED carries the failure reason in
code; any other value (PENDING, OPEN, FILLED, …) means the order
was accepted. This response never reports PARTIAL: a partly filled
resting order is OPEN with a non-zero filledQty.
Vault signature requests — standard error envelope
POST /api/vault/{split,merge,convert}-signature rejects — like any
non-2xx response elsewhere — use the standard error envelope
described at the top of this page: the outer status numeric mirrors
the HTTP status, and the actual error code lives under error.code:
trace_id matches the X-Trace-Id header on the response — quote it
when filing tickets. On 4xx rejects details carries endpoint-specific
context (rate-limit windows, conflicting state, etc.); on 5xx it is
omitted.
Upstream errors — flattened to error.code directly
Errors raised behind the API gateway (matching, vault signing,
withdrawals) reach you with the original code surfaced at the top
of the envelope:
POST /api/orders/place upstream rejects,
POST /api/me/withdrawals/{id}/cancel (invalid_state,
withdrawal_not_found) and POST /api/vault/{split,merge,convert}-signature
rejects. Branch on error.code directly — the upstream code is
lifted to the top level, so the /errors/codes
catalogue is canonical wherever the rejection originated.
On these
4xx answers the original rejection is also attached, as
error.details.details.upstream ({status, body}), for logging and
diagnostics only — rely on top-level error.code exclusively. A 5xx
never carries it (see the top of this page). When the original
rejection has no machine-readable code (an HTML proxy page, an empty
body, raw text), error.code is exchange_upstream_error and the raw
answer sits in the same upstream wrapper.Why two shapes
POST /api/orders/place and each entry of
POST /api/orders/place-batch return the fill record even on a reject
(zero fills, zero trades), so success and reject share one schema and
the HTTP status stays 201. Vault signature endpoints have no fill
record to return; they use the platform-wide HTTP error envelope.
On a placement, code is present only when status is REJECTED. On
an error response, the code is error.code; there is no top-level
code. Branch on status for placements and on error.code for
errors.
Error codes
Complete code reference across all endpoints.