Skip to content

Trading

Order lifecycle

An order moves through a fixed set of states from the moment you submit it until it fills or is cancelled. Every state is observable through the API.

Endpoints in this chapter

Four endpoints cover the entire order lifecycle. All trading endpoints require authentication and the appropriate scope.

VerbPathPurpose
POST /orders Submit a new order.
GET /orders/:id Read a single order by ID.
GET /orders List your open and recently closed orders.
POST /orders/:id/cancel Cancel an open order.
ACTORClientACTORSatoriEx APIACTORRedis LISTACTORMatcherACTORLedgerACTORWebSocket Hub1POST /orders (validate, escrow funds)2202 Accepted (trades: [])3LPUSH order:pending4BRPOP (pull next order)5match by price-time priority6atomic debit / credit (double-entry)7broadcast trade event over /wsAll seven steps run in the same matcher tick โ€” typical end-to-end latency from POST to WS event is under 500 ms.
The full async flow from a POST /orders call to a trade event delivered over WebSocket. The 202 Accepted (step 2, dashed) lands BEFORE matching runs โ€” your client must await the trade event on /ws to learn the fill outcome.

Order states

Every order carries one of these state values. State transitions are one-way except for partial-then-cancelled. There is no time-in-force expiry โ€” orders rest until filled or explicitly cancelled.

ENTRYSubmittedSTATEpendingSTATEopenSTATEpartialSTATEfilledEXITClosedSTATEcancelledPOST /ordersadded to booksome fillsmore fillsfully matchedvalidation failsuser cancelscancel remainder
Transitions are one-way except for the cancel branches: pending, open, and partial can all transition to cancelled by user or admin action. A circuit-breaker halt pauses the market but leaves resting orders intact โ€” cancellation is still your decision. Cancelling a partial order removes only the unfilled remainder.
StateMeaning
pendingValidated and queued; awaiting the matching engine.
openResting in the order book waiting for a counter-order.
partialFilled in part; the remainder is still resting.
filledFully matched. Shares are in your position.
cancelledCancelled by the user or by an admin action. The circuit breaker halts the market on a 30%+ price move but does not automatically cancel resting orders โ€” they are paused until trading resumes (or you cancel them yourself).

Common rejection reasons

When an order is rejected, the response carries a stable numeric error code that your client can branch on, plus a human-readable message that may be localized.

CodeSymbolMeaning
3001 ErrInsufficientBalance your USDC balance is too low for the order at the proposed price.
5002 ErrInvalidPrice the price is outside the market's accepted tick range or below 0 / above 1.
5004 ErrInvalidSide side must be 1 (buy) or 2 (sell) โ€” any other value is rejected.
5007 ErrMarketNotTrading the market is halted (circuit breaker, resolution, or maintenance).
5008 ErrInsufficientPosition you do not hold enough shares of this outcome to place this sell order.
2025 ErrTwoFactorRequired 2FA is required for trading โ€” enable it in Security settings before placing orders.

Branch on the numeric `code` field, not on the message โ€” messages are user-facing and change with locale and platform copy.

Subscribe to order events instead of polling

The WebSocket order channel pushes state transitions in real time. Use it for any bot that needs to react to fills โ€” polling is acceptable for dashboards but wasteful for trading loops.