Skip to main content
Every error has the same shape:
Branch on code, never on message. Codes are stable; messages are not.

origin tells you whether it happened

This is the field worth understanding, because it answers “did my order exist?” For a retry decision: gateway and port rejects are safe to fix and resend. A core reject is a real economic answer, resending unchanged gets the same result.

Common codes

Authentication

Your request was malformed

The exchange said no

Timeouts are not rejections

A 504 is the one case where “it failed” is the wrong assumption. The request timed out waiting for sequencing; it may well have been sequenced. Always resolve it with the same client_order_id, that is what the idempotency key is for. Retrying with a fresh id is how you end up with two orders.

Cancellations are not errors

Post-only orders that would cross, unfillable FOKs, IOC remainders, self-trade prevention, and off-grid rests after a tick-grid coarsen all come back as a successful 201 with status: "canceled" and a reason. They are execution outcomes, not failures, so check status on success responses rather than assuming 201 means resting. reason: "tick_size" means the rest was cancelled because it was no longer on the live grid.

Full error registry

Branch on code. The table below is the full registry the venue emits today.

Gateway (origin: "gateway", num: null)

Core (origin: "core", num set)

Sequenced rejects, the request happened and is in the audit log.

Port (origin: "port")

Edge rejects at the order-entry port, never sequenced, no stream record.
Funding-port rejects carry origin: "port" but num: null, funding reject codes use a separate enum, not the shared registry.