> For the complete documentation index, see [llms.txt](https://docs.reya.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.reya.xyz/developers/order-entry/order-lifecycle.md).

# 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](/developers/authentication/signatures-and-nonces.md)) and submit over [REST](/developers/api-reference/rest-api-reference.md) or [WS Order Entry](/developers/api-reference/ws-exec-api-reference.md).
2. **Accepted by the matching engine** — validated, with [pre-trade risk checks](/developers/risk/margin-system.md#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`](#modifying-a-resting-order) 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)](/developers/order-entry/trigger-orders.md).
3. **Terminal.** The order reaches `FILLED` or `CANCELLED`, and any fills proceed to on-chain settlement (see [Trade Settlement](/developers/executions-and-settlement/settlement.md)).

All orders publish state changes on the [`orderChanges`](/developers/api-reference/websocket-api-reference.md) 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](/developers/executions-and-settlement/executions-and-trade-history.md) and [Trade Busts](/developers/executions-and-settlement/trade-busts.md).

## Average fill price

{% hint style="info" %}
`avgFillPx` was introduced in API **3.5.4**. See the [release entry and canonical spec](/developers/changelog/changelog.md#log).
{% endhint %}

`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](/developers/executions-and-settlement/executions-and-trade-history.md) 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)](/developers/order-entry/trigger-orders.md#choosing-the-fired-childs-time-in-force). See [Signatures & Nonces](/developers/authentication/signatures-and-nonces.md) 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](/developers/order-entry/cancel-on-disconnect.md) for bounds, request fields, signing, and error codes.

## Modifying a resting order

The request rules below follow API **3.6.2**; see the [changelog](/developers/changelog/changelog.md#log) 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)](/developers/order-entry/trigger-orders.md#re-pricing-modify).
* **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](/developers/authentication/signatures-and-nonces.md).
* **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](/developers/order-entry/order-types-and-tif.md)).

## 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`](#modifying-a-resting-order) rather than cancelling and re-placing. The account-scoped [`cancelAllAfter`](#cancel-on-disconnect-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)](/developers/order-entry/trigger-orders.md#firing-oco-and-self-trades).
* **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](/developers/risk/margin-system.md#handling-risk-outcomes) are temporarily unavailable, and is handled the same way. A rejected crossing request still uses a create/modify operation; see [Rate Limits](/developers/connectivity/rate-limits.md#account-operation-limits).
