Skip to main content
The orderUpdates channel sends incremental state changes for every order associated with an account — the moment an order is placed, partially filled, fully filled, cancelled, or rejected, when a conditional (TP/SL) order changes state, and when a resting order is filled by another order. Entries come in five kinds, each with its own field set, and one frame can mix several kinds — see Telling the entry kinds apart. On subscribe the server first sends one frame of recent order history (see History snapshot on subscribe); live increments follow. That snapshot contains only orders that have already terminated — for a full view of orders currently resting, subscribe to openOrders or query userOrders. Pass the account’s wallet address (not the numeric account ID) as the user parameter, in lowercase 0x + 40 hex form. The address must belong to a registered account.

Subscribing

Push envelope

All order update messages share this envelope structure:
The data array may contain multiple entries when several orders change state in the same block.

Regular order entry

This entry is sent for an order you place, including when it fills on arrival as the taker.

Field reference

On a regular entry tp is an object; on a conditional entry tp is a scalar trigger price. Check for "cond": true before parsing it.

History snapshot on subscribe

Immediately after a successful subscription the server pushes one frame carrying up to the last 10 terminated orders, so a client can render history without a separate REST call. It differs from an incremental frame in two ways:
rows[] uses different field names from the incremental entries — you cannot reuse one parser for both. A private-channel snapshot passes through the corresponding REST response body verbatim, so it uses the full REST column names (order_id, contract_id, price) while increments use the compact wire names (id, c, p). Reuse your REST parser for the snapshot.

Snapshot row fields

Working with the snapshot:
  • The payload is at data.rows, and data is an object rather than an array. (openOrders also sends an object, but its payload key is orders.)
  • Quoted fields are big integers carried as strings (order_id, cl_ord_id, price, every *_qty). They can exceed the JavaScript safe-integer range — never pass them through Number() before comparing or echoing them back.
  • side, ord_type, and status are numeric here and strings in the incremental frames. Map them before display.
  • It contains only terminated orders. Orders still working are not included — use the openOrders first frame or userOrders for those.
  • Fewer than 10 rows, or none at all, is normal — the account may have little history, or the history service may be briefly unavailable. Do not treat it as an error.
  • The snapshot and the increments that follow may overlap. Deduplicate by order ID (order_id in the snapshot, id in increments); nothing is dropped.
  • The snapshot is fixed at 10 rows, with no paging and no cursor. For deeper history use orderHistory.

Cancel entry

When an order is cancelled, a compact entry is sent with "st": "Canceled".
A cancel entry has no t or tif. In the example, an order of 1000 filled 300 before the remaining 700 was cancelled.

Rejected order entry

If an order placement or a cancel is rejected (for example, the contract doesn’t exist, insufficient margin, or a position-mode mismatch), a "st": "Rejected" entry is pushed here. A rejected order appears only on this channel — it is never assigned an order ID, never appears in openOrders, and cannot be found by any order-ID or client-order-ID query.
A rejected entry omits t / tif / p / s — the order never became active, so it has none of those attributes. b appears only when a valid direction can be resolved. Rejected placements and rejected cancels share this entry kind.

Conditional (TP/SL) order entry

Conditional orders include "cond": true and use a different set of status values:
Additional fields for conditional orders:
otp* / osl* describe the TP/SL of the order created after triggering. They are a separate layer from this entry’s own trigger price tp and trigger type tpt.
Conditional order statuses: A market order created by a trigger executes as IOC, so if it fills only partially, its regular entry arrives with the final status Canceled.

Passive fill entry

When another order fills one of your resting orders, you — the maker — receive this entry:
This entry carries no r, si, cid, tif, tp, or sl. Match it to your order by id (available from the regular entry after placement, or from userOrders). The taker does not receive this entry; it receives a regular entry. For fill price, size, and fee, use the userFills channel.

Telling the entry kinds apart

Check the conditions in this order:
tp is an object on a regular entry and a string (trigger price) on a conditional entry. The entry-level ts (conditional entries only, creation time) differs from the envelope ts (send time). Identify the entry kind first, then read its fields.
Set a client order ID (cid) when you place an order, then match incoming OrderUpdates on cid to link each update back to your submission — especially useful when placing orders in rapid succession. The r request ID is server-assigned and unknown at submit time, so it cannot serve as the correlation key. A rejected order never receives an id, so it is correlated by the nonce you signed (see Rejected order entry).