For the complete documentation index, see llms.txt. This page is also available as Markdown.

Order Lifecycle

The states an order moves through, and the two time controls that govern it.

The path of an order

  1. Signed. You sign the OrderDetails (see Signatures & Nonces) and submit over REST or WS Order Entry.

  2. Accepted by the matching engine — validated, with pre-trade risk checks before fills are committed:

    • IOC fills what it can immediately and cancels the remainder. It never rests on the book, but the matching engine still issues an order ID for it.

    • GTC rests on the book (with an order ID) until it fills or you cancel it.

    • GTT rests like GTC, but it is automatically cancelled once its signed expiresAfter timestamp passes — emitting a CANCELLED orderChange. You can refresh a resting GTT's expiresAfter with modifyOrder instead of letting it expire.

    • Trigger (STOP_LOSS / TAKE_PROFIT) — durably armed outside the book, then fired against the mark price into the chosen IOC/GTC/GTT child. Only the armed phase is modifiable. A user cancelAll clears both armed triggers and fired children; Cancel-on-Disconnect preserves both. Full contract: Trigger Orders (SL/TP).

  3. Terminal. The order reaches FILLED or CANCELLED, and any fills proceed to on-chain settlement (see Trade Settlement).

All orders publish state changes on the orderChanges channel. These are matching-engine-level signals. Request errors are returned as errors, not order-status updates. Settled fills are confirmed only on the executions channel; see Executions & Trade History and Trade Busts.

Average fill price

avgFillPx was introduced in API 3.5.4. See the release entry and canonical spec.

avgFillPx is the quantity-weighted average execution price across all fills of an order so far, including both maker (passive) and taker (aggressive) fills, excluding fees. It corresponds to the order's cumulative filled quantity, cumQty.

avgFillPx = sum(fill price × fill quantity) / cumQty

The field is a decimal string, calculated from the exact fill prices and quantities and rounded half-up once to at most 9 decimal places. It is omitted before the first fill, when cumQty is zero. The cumulative average is preserved across amendments of the same order and cancellation; a modify with no new fill keeps the previous average.

The field is included after the first fill on:

  • REST and WebSocket Order Entry createOrder and modifyOrder responses, including IOC create responses.

  • WebSocket Info orderChanges updates and the subscription's open-orders snapshot.

  • REST openOrders and orderHistory records.

For example, an order that first takes liquidity and later fills as a maker reports:

New fill

Role

cumQty

avgFillPx

1 at 100

Taker

"1"

"100"

2 at 110

Maker

"3"

"106.666666667"

1 at 120

Maker, after amend

"4"

"110"

execQty reports the quantity filled in the current update, while avgFillPx covers all fills represented by cumQty. Individual settled executions continue to carry their own price. Like the other order-outcome fields, avgFillPx describes matching-engine results before settlement; use the executions channels to confirm settled fills.

deadline vs expiresAfter

Two independent time fields, both signed:

Field
Governs
Enforced

deadline

How long the signed request is valid for entry

At submission

expiresAfter

When a resting GTT order auto-expires

While the order is active and at settlement

Both are Unix-second timestamps. deadline is required on every order; expiresAfter carries a lifetime only for GTT orders (where it must be strictly greater than deadline) and is omitted for GTC and IOC, including triggers with those TIFs. Once expiresAfter passes, the GTT is automatically cancelled with a CANCELLED orderChange. A GTT trigger and its fired child instead share an immutable expiry and stop early to allow time for settlement; see Trigger Orders (SL/TP). See Signatures & Nonces for the encoding.

Cancel-on-Disconnect (cancelAllAfter)

Cancel-on-Disconnect is an account-scoped dead-man's switch driven by cancelAllAfter. You arm a countdown; if you don't refresh it before it elapses, the matching engine cancels every open order on the account — across all markets, spot and perp — except protective stops (STOP_LOSS / TAKE_PROFIT), which it deliberately keeps. A WebSocket close neither fires nor disarms it — only the countdown elapsing does. See Cancel-on-Disconnect for bounds, request fields, signing, and error codes.

Modifying a resting order

The request rules below follow API 3.6.2; see the changelog for release history.

modifyOrder (REST POST /v2/modifyOrder, or the modifyOrder WebSocket Order Entry message) amends one order in place — a resting LIMIT (GTC or GTT, spot or perp) or an armed STOP_LOSS / TAKE_PROFIT trigger. The order keeps its orderId and clientOrderId.

  • Full restate. The request carries the complete post-modify OrderDetails state plus a target id — you restate every value, even unchanged ones; omission never inherits from the resting order. It uses the same signed EIP-712 field universe as createOrder, but its JSON fields are class-specific: trigger create and modify require timeInForce and omit reduceOnly and postOnly, including false. Both Boolean fields are reconstructed as fixed false for signing and verification; they are never inherited from stored state. The modifiable set is class-split:

    • LIMIT — limitPx, qty, postOnly, expiresAfter (triggerPx is forbidden):

      • qty is the total post-modify order quantity and must exceed cumQty (else MODIFY_QTY_BELOW_FILLED_ERROR).

      • expiresAfter — GTC omits it; GTT must carry a future value greater than deadline.

    • STOP_LOSS / TAKE_PROFIT — only limitPx and triggerPx: triggerPx re-prices the armed trigger in place (no cancel-and-recreate) and is required; qty stays omitted, both Boolean flags stay omitted, and the originally chosen TIF and original expiry (present only for GTT) are restated immutables. A fired child is cancel-only. See Trigger Orders (SL/TP).

  • Immutables must be restated to match. The remaining OrderDetails fields — isBuy / side, exchangeId, orderType, timeInForce, reduceOnly (LIMIT only; triggers omit it), clientOrderId, accountId, signerWallet — are immutable: restate them at the resting order's values. A mismatch is rejected with INPUT_VALIDATION_ERROR. timeInForce is immutable — you cannot switch GTC ↔ GTT via modify; orderType is immutable — a modify re-prices a trigger but never converts between LIMIT and STOP_LOSS / TAKE_PROFIT.

  • Target by orderId when present, otherwise by a non-zero clientOrderId. The same clientOrderId field restates the resting order's immutable client id for signing. If both identifiers are supplied, orderId is canonical for lookup and clientOrderId is the restated immutable. If the resting order has no client id, omit clientOrderId; do not send a placeholder value. Supplying neither is rejected with INPUT_VALIDATION_ERROR.

  • Crossing. For a LIMIT order, a non-post-only modify whose new limitPx crosses executes immediately and settles like a crossing create. A post-only modify that would cross is rejected with POST_ONLY_WOULD_CROSS_ERROR and the resting order is left untouched.

  • Signing. A fresh OrderDetails EIP-712 envelope over the full post-modify state with a fresh nonce — the same envelope and type as createOrder. Verification uses the restated values plus the fixed trigger Boolean values described above. See Signatures & Nonces.

  • Errors (client-facing codes): ORDER_NOT_FOUND_ERROR; INPUT_VALIDATION_ERROR (a restated immutable differs from the resting order, or timeInForce/expiresAfter are inconsistent); EMPTY_MODIFY_ERROR (no field actually changed); MODIFY_QTY_BELOW_FILLED_ERROR; POST_ONLY_WOULD_CROSS_ERROR; MODIFY_ORDER_OTHER_ERROR (another modify rejection; read the returned message); UNAUTHORIZED_SIGNATURE_ERROR; NUMERIC_OVERFLOW_ERROR.

modifyOrder is also how you refresh a GTT's expiresAfter without re-placing the order (see Order Types & Time-in-Force).

Cancelling

Cancel a specific order (cancelOrder) or all your orders (cancelAll) — both require a valid signature, for spot and perp alike. To amend a resting order without losing its ID, use modifyOrder rather than cancelling and re-placing. The account-scoped cancelAllAfter dead-man's switch is a third member of the cancel family: it arms a timer that cancels every open order on the account if you stop refreshing it.

Matching pauses

When on-chain settlement falls behind, Reya temporarily pauses matching so that unsettled fills stop building up. Order entry stays open: only requests that would fill are refused. Design your client to handle CROSSING_ORDERS_TEMPORARILY_UNAVAILABLE_ERROR as a temporary rejection.

Matching pauses when:

  • settlement transactions for matched fills are failing to broadcast;

  • on-chain confirmation of fills already sent for settlement is lagging; or

  • fills are waiting too long to settle — the oldest waiting fill is more than about 30 seconds old. This cause clears once the backlog drains below about 5 seconds.

Matching resumes automatically once these conditions clear.

While matching is paused:

  • Orders that would fill are rejected. A createOrder or modifyOrder that would cross the book is rejected with CROSSING_ORDERS_TEMPORARILY_UNAVAILABLE_ERROR — including reduce-only orders. Nothing is placed, and a rejected modify leaves the resting order unchanged.

  • Resting orders don't fill. Only an incoming crossing order can trade, so nothing on the book fills until matching resumes.

  • You can still place and re-price resting orders. A createOrder that doesn't cross rests on the book, and a modifyOrder that re-prices a resting order without crossing is applied. A post-only order that would cross is still rejected with POST_ONLY_WOULD_CROSS_ERROR.

  • Triggers can be placed and modified, but don't fire. You can create, modify, and cancel STOP_LOSS / TAKE_PROFIT orders. Armed triggers stay armed and can fire once matching resumes; see Trigger Orders (SL/TP).

  • Cancels remain available. You can use cancelOrder, cancelAll, and cancelAllAfter.

Treat the rejection as temporary. Back off, then retry the crossing request if it is still appropriate — prices and your position may have moved in the meantime. The same error is returned when pre-trade risk checks are temporarily unavailable, and is handled the same way. A rejected crossing request still uses a create/modify operation; see Rate Limits.

Last updated