> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.immix.xyz/api-reference/trading/orders/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.immix.xyz/_mcp/server. # Orders **`Request — sent`** ```json title="Request — sent" { "op": "subscribe", "reqId": "", "params": { "topics": [ "order" ] } } ``` **`Response — received`** ```json title="Response — received" { "op": "subscribe", "reqId": "", "success": true } ``` **`orderUpdate · snapshot part — received`** ```json title="orderUpdate · snapshot part — received" { "event": "order", "msgType": "orderUpdate", "topic": "order", "seq": "", "seqTs": "", "isSnapshot": true, "snapshotId": "", "part": 0, "last": true, "data": [ { "orderId": "", "version": "", "clientOrderId": "", "accountId": 0, "account": "", "instrumentId": "", "instrument": "", "credentialId": 0, "userId": 0, "side": "UNKNOWN", "orderType": "UNKNOWN", "timeInForce": "UNKNOWN", "postOnly": true, "reduceOnly": true, "price": "", "qty": "", "status": "UNKNOWN", "live": true, "terminal": true, "cancelRequested": true, "transition": "UNKNOWN", "reason": "USER_REQUESTED", "venueCode": 0, "message": "", "venueText": "", "cumQty": "", "leavesQty": "", "avgPx": "", "lastFillQty": "", "lastFillPx": "", "venueCumQty": "", "executionsComplete": true, "acceptedAtNs": "", "instructedAtNs": "", "cancelRequestedAtNs": "", "venueTsNs": "", "tradingPolicyId": 0, "tradingPolicyVersion": "", "venueOrderId": "" } ] } ``` **`orderUpdate · delta — received`** ```json title="orderUpdate · delta — received" { "event": "order", "msgType": "orderUpdate", "topic": "order", "seq": "", "seqTs": "", "isSnapshot": false, "data": [ { "orderId": "", "version": "", "clientOrderId": "", "accountId": 0, "account": "", "instrumentId": "", "instrument": "", "credentialId": 0, "userId": 0, "side": "UNKNOWN", "orderType": "UNKNOWN", "timeInForce": "UNKNOWN", "postOnly": true, "reduceOnly": true, "price": "", "qty": "", "status": "UNKNOWN", "live": true, "terminal": true, "cancelRequested": true, "transition": "UNKNOWN", "reason": "USER_REQUESTED", "venueCode": 0, "message": "", "venueText": "", "cumQty": "", "leavesQty": "", "avgPx": "", "lastFillQty": "", "lastFillPx": "", "venueCumQty": "", "executionsComplete": true, "acceptedAtNs": "", "instructedAtNs": "", "cancelRequestedAtNs": "", "venueTsNs": "", "tradingPolicyId": 0, "tradingPolicyVersion": "", "venueOrderId": "" } ] } ``` **`orderRejected — received`** ```json title="orderRejected — received" { "event": "order", "msgType": "orderRejected", "topic": "order", "seq": "", "seqTs": "", "isSnapshot": false, "data": [ { "command": "UNKNOWN", "reason": "UNKNOWN", "message": "", "clientOrderId": "", "orderId": "", "accountId": 0, "account": "", "instrumentId": "", "instrument": "", "userId": 0, "observedValue": "", "limitValue": "", "unit": "PRICE", "tradingPolicyId": 0, "tradingPolicyVersion": "" } ] } ``` Each frame is its shape, read off the contract: `` stands for a value, and a union shows its first form. **URL** — No public environment serves this socket yet. **Topic** `order` ## Request parameters | Parameter | Type | Required | Description | | ---------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------- | | `op` | string | Yes | `subscribe` | | `reqId` | string | Yes | Echoed byte-exact on the answer. Printable ASCII, escape-free; anything else answers MALFORMED. | | `params` | object | Yes | | | > `topics` | array of strings | Yes | `order` | ## Response parameters | Parameter | Type | Required | Description | | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------- | | `op` | string | Yes | One of `subscribe`, `unsubscribe`. | | `reqId` | string | Yes | Echoed byte-exact on the answer. Printable ASCII, escape-free; anything else answers MALFORMED. | | `success` | boolean | Yes | `true` | ## Push data parameters · orderUpdate `live` and `terminal` are the forward-compatible reads: a status appended to the platform's schema later arrives with both booleans already set, so a client that buckets on them never mis-buckets a status it has not heard of. Bucket on those, not on `status`. `cancelRequested` is live and a cancel in flight — a fact about an order, not a different kind of order. **Two voices explain a row, and a client shows both.** `message` is the platform's own words for `reason`; `venueText` is whatever the venue said, verbatim. They are not alternatives: where the venue is the one that decided, `message` is the framing ("the venue rejected this order") and `venueText` is the substance ("insufficient margin"). Where the platform decided — `OWNER_TIMEOUT`, `INSTRUCTION_FRESHNESS_EXPIRED`, `RECONCILE_PROOF` — no venue said anything and `message` is the only text there is. **Render `message`, then `venueText` after it when present.** Both are null on the ordinary path, where a row states no reason at all. **What the image holds.** Every order of the organization this member retains, keyed by `orderId`: every **live** order whatever its age, and a **terminal** order whose last venue timestamp — or its acceptance, when the venue stated none — falls inside the served window, 24 hours by default and a per-deployment setting. A terminal order older than the window is not in a new image, though a delta for it would still arrive; it is not gone, it is out of scope, and order history is a query lane's job rather than this one's. **How a row leaves.** Only by the platform releasing it under its own retention, and **that release rides no wire** — there is no removal message and no tombstone. A client learns a row is gone by re-subscribing and rebuilding its map from the image, which is exactly what `part: 1` clearing the map is for. Nothing else ever removes a row; a terminal order stays in your map, and `terminal` is what marks it. | Parameter | Type | Required | Description | | ------------------------ | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `event` | string | Yes | `order` | | `msgType` | string | Yes | `orderUpdate` | | `topic` | string | Yes | `order` | | `seq` | string | Yes | The stream position, as a decimal string — an int64 a JSON number would truncate. | | `seqTs` | string | Yes | The stream timestamp, epoch-ns as a decimal string. | | `isSnapshot` | boolean | Yes | One of `true`, `false`. | | `snapshotId` | string | No | **Present on a snapshot part only**, and the same on every part of one image; the next image of any topic carries a different one. **Opaque — compare it for equality and nothing else.** It is not a sequence, a version or a timestamp, and its shape may change; a client that ordered by it would be relying on how a member happens to mint it. Use it to keep two images apart. A repeat `subscribe` re-pushes the image — that is the resync, and there is no separate op — so a client can start image N+1 while N is still arriving, and without a name on each part it cannot tell which `last: true` closes which, nor stop a straggling part of N landing in the map N+1 just cleared. **Discard any part whose `snapshotId` is not the one you are currently applying.** | | `part` | integer | No | Present on a snapshot part only; 1-based. | | `last` | boolean | No | Present on a snapshot part only. The image is complete when true — including for an empty channel, which is still one part. | | `data` | array of objects | Yes | One order's applied image, keyed by `orderId`. Upsert by that key into the map `part: 1` cleared. | | > `orderId` | string | Yes | The upsert key, as a decimal string — an int64. | | > `version` | string | Yes | | | > `clientOrderId` | string, nullable | Yes | The id the submitter chose; null when it sent none. | | > `accountId` | integer | Yes | | | > `account` | string, nullable | Yes | The account's display name; null when the referenced row is not held. | | > `instrumentId` | string | Yes | An instrument, by the platform's own id — an int64 as a decimal string, because a JSON number cannot hold one. **One id space across this wire and the HTTP lane**, and the same one both order doors take: the id you read here is the id you send, on `submitOrder` and on `POST /orders` alike. It is **the platform's own reference-data key and nothing else's**. It is not a venue symbol, and it is not an id from any other system — in particular it does **not** equal an immix-api v2 `Instrument.id`, and there is no arithmetic that maps between them. A client holding v2 ids resolves through the symbol, once, at cutover: `instrument` beside this field carries the platform symbol (`OKX@BTC/USDT`), which is what both systems can be joined on. The id is the stable address and the symbol is the convenience: a symbol is reference data's to change and this id is not. | | > `instrument` | string, nullable | Yes | | | > `credentialId` | integer | Yes | | | > `userId` | integer | Yes | Who SUBMITTED, never restamped. Attribution of a cancel is a different question and this field does not answer it. | | > `side` | string | Yes | One of `UNKNOWN`, `BUY`, `SELL`. | | > `orderType` | string | Yes | One of `UNKNOWN`, `LIMIT`, `MARKET`. | | > `timeInForce` | string | Yes | GTD is reserved and never appears on this wire in v1. One of `UNKNOWN`, `GTC`, `IOC`, `FOK`, `GTD`. | | > `postOnly` | boolean | Yes | | | > `reduceOnly` | boolean | Yes | Always false in v1; the platform refuses reduceOnly outright. | | > `price` | string, nullable | Yes | Exact decimal at the record's price scale, trailing zeros kept. Null for a MARKET order, which has no price rather than a zero one. | | > `qty` | string | Yes | | | > `status` | string | Yes | Do NOT bucket on this. A status appended to the platform's schema later is a value you have not heard of; bucket on `live` and `terminal`, which arrive already set for it. One of `UNKNOWN`, `QUEUED`, `INSTRUCTED`, `OPEN`, `PARTIALLY_FILLED`, `FILLED`, `CANCELED`, `REJECTED`, `EXPIRED`, `INSTRUCTION_EXPIRED`, `EXPIRED_UNCONFIRMED`, `NOT_FOUND_AT_VENUE`. | | > `live` | boolean | Yes | | | > `terminal` | boolean | Yes | | | > `cancelRequested` | boolean | Yes | Live, with a cancel in flight — a fact about an order, not a different kind of order. | | > `transition` | string | Yes | Advisory. On a snapshot row it reads SNAPSHOT: the durable transition belongs to a fact, and a snapshot is not one. One of `UNKNOWN`, `SUBMITTED`, `INSTRUCTED`, `ACKNOWLEDGED`, `OPENED`, `TRADE`, `CANCEL_REQUESTED`, `CANCEL_REJECTED`, `CANCELED`, `REJECTED`, `EXPIRED`, `INSTRUCTION_EXPIRED`, `EXPIRED_UNCONFIRMED`, `NOT_FOUND_AT_VENUE`, `RECONCILE_REQUESTED`, `RESTATED`, `SNAPSHOT`. | | > `reason` | string, nullable | Yes | Null when the record states no reason. One of `USER_REQUESTED`, `VENUE_INITIATED`, `POST_ONLY_WOULD_CROSS`, `MMP`, `SELF_TRADE_PREVENTED`, `IOC_REMAINDER`, `FOK_UNFILLED`, `UNSUPPORTED_AT_VENUE`, `VENUE_REJECTED`, `INSTRUCTION_FRESHNESS_EXPIRED`, `RECONCILE_PROOF`, `OWNER_TIMEOUT`, `VENUE_REFERENCE_MISSING`. | | > `venueCode` | integer, nullable | Yes | | | > `message` | string, nullable | Yes | **The platform's own words for `reason`** — display text, null exactly when `reason` is null. Branch on `reason`, the stable name; this sentence may be reworded in any release and carries no numbers. **Show it beside `venueText`, never instead of it.** The two are different voices: this one is the platform's, `venueText` is the venue's. Where the venue is the one that decided — `VENUE_REJECTED` above all — this reads "the venue rejected this order" and the venue's own text holds why ("insufficient margin"). A client that rendered one *or* the other would hide the informative half exactly when it mattered. Render `message`, and render `venueText` after it when it is present. | | > `venueText` | string, nullable | Yes | **Whatever the venue said, verbatim** — the venue's voice, never the platform's. Display it; do not parse it. Null whenever no venue said anything, which includes every reason the platform decides for itself (`OWNER_TIMEOUT`, `INSTRUCTION_FRESHNESS_EXPIRED`, `RECONCILE_PROOF`): for those, `message` is the only text there is. | | > `cumQty` | string | Yes | | | > `leavesQty` | string | Yes | | | > `avgPx` | string, nullable | Yes | Null with no fills. | | > `lastFillQty` | string, nullable | Yes | | | > `lastFillPx` | string, nullable | Yes | | | > `venueCumQty` | string, nullable | Yes | Null means the venue never reported a cumulative. A reported cumulative of zero is a value, and says something different. | | > `executionsComplete` | boolean | Yes | | | > `acceptedAtNs` | string, nullable | Yes | Epoch-ns as a decimal string; null when the stamp is unset. | | > `instructedAtNs` | string, nullable | Yes | | | > `cancelRequestedAtNs` | string, nullable | Yes | | | > `venueTsNs` | string, nullable | Yes | | | > `tradingPolicyId` | integer, nullable | Yes | | | > `tradingPolicyVersion` | string, nullable | Yes | | | > `venueOrderId` | string, nullable | Yes | The venue's own id for the order; null before the venue names one. | ## Push data parameters · orderRejected The `order` topic's **second shape**. A `submitOrder` or `cancelOrder` that was offered and then refused at admission arrives here, correlated by the `clientOrderId` you sent (or by `orderId` for a cancel that named one). This is the other half of the offer contract: an ack told you the command reached the stream, and one of `orderUpdate status: QUEUED` or `orderRejected` tells you what became of it. **It is never in a snapshot**, and `isSnapshot` is `false` here by construction. A refusal is a fact no fold holds: nothing was minted, so there is no row to retain or restore. A client that replaces its blotter on `last: true` will not get its refusals back — they are live-only, and history is a query lane's job. Do not key a map on them. Switch on `msgType`. Both shapes carry `event: order` and `topic: order`, because they are the same subscription; `msgType` is the discriminator and it is a const on both. | Parameter | Type | Required | Description | | ------------------------ | ----------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `event` | string | Yes | `order` | | `msgType` | string | Yes | `orderRejected` | | `topic` | string | Yes | `order` | | `seq` | string | Yes | The stream position, as a decimal string — an int64 a JSON number would truncate. | | `seqTs` | string | Yes | The stream timestamp, epoch-ns as a decimal string. | | `isSnapshot` | boolean | Yes | `false` | | `data` | array of objects | Yes | One refused command. **Not an order** — do not upsert it into the blotter map. A refused submit minted nothing, so `orderId` is null; a refused cancel names the order it addressed. `observedValue` and `limitValue` are the refusal's detail pair — what the command carried and the bound it breached — and `unit` says what they measure. Both legs are decimal strings at the scale the reason states, and all three are null together when the reason is about identity, capability or state rather than a quantity. Whether a pair is stated is a property of the refusing arm, not of the reason: the same `reason` can refuse bare on one arm and with a measured pair on another, so read the pair's own nullness and never infer it from `reason`. `unit` is derived by this edge, not carried by the platform's schema, which is precisely why it is on the wire: without it a client would have to guess from magnitude whether a `5` is basis points or a count of orders. `reason` is the stable name — switch on it. `message` is display text for a human and may be reworded in any release; never branch on it. | | > `command` | string | Yes | Which command was refused. `ATTRIBUTE` is an internal attribution command that no client op produces — it can never answer your `submitOrder` or `cancelOrder`, and a client may treat it exactly as it treats a value it does not know. Tolerate an unknown value: this enum is appended to as the owner's surface grows. One of `UNKNOWN`, `SUBMIT`, `CANCEL`, `ATTRIBUTE`. | | > `reason` | string | Yes | Why the owner refused. A closed enum **that is appended to** — tolerate an unknown value and fall back to `message`. The first failing check wins, deterministically, so exactly one reason describes a refusal. One of `UNKNOWN`, `CLIENT_ORDER_ID_CONFLICT`, `ORG_MISMATCH`, `ACCOUNT_NOT_ACTIVE`, `CAPABILITY_DENIED`, `INSTRUMENT_NOT_LIVE`, `CREDENTIAL_UNAVAILABLE`, `CONNECTION_DOWN`, `TRADING_POLICY_MISSING`, `TRADING_HALTED`, `INVALID_FIELD`, `UNSUPPORTED_AT_VENUE`, `NO_REFERENCE_PRICE`, `TICK_SIZE_VIOLATION`, `QTY_STEP_VIOLATION`, `QTY_BOUND_BREACH`, `MIN_NOTIONAL_BREACH`, `TICKET_QTY_CAP_EXCEEDED`, `TICKET_NOTIONAL_CAP_EXCEEDED`, `COLLAR_BREACH`, `OPEN_ORDER_CEILING`, `RATE_CEILING`, `UNKNOWN_ORDER`, `ORDER_TERMINAL`, `PRICE_BOUND_BREACH`, `ORDER_STATUS_UNKNOWN`, `ORG_NOT_ACTIVE`, `FILL_PRECISION_OVERFLOW`. | | > `message` | string | Yes | Display text for `reason`. Display only. | | > `clientOrderId` | string, nullable | Yes | The id you sent, echoed. Null for a command that carried none — a cancel by `orderId`. | | > `orderId` | string, nullable | Yes | The order the command addressed, as a decimal string. Null for a refused submit: no order was minted. | | > `accountId` | integer, nullable | Yes | Null when the refusing check fired before the account resolved. | | > `account` | string, nullable | Yes | The account's display name; null when unresolvable here. | | > `instrumentId` | string, nullable | Yes | A decimal string; null when the refusing check fired before resolution. | | > `instrument` | string, nullable | Yes | The instrument's symbol; null when unresolvable here. | | > `userId` | integer | Yes | The acting user the edge stamped; 0 for a machine. | | > `observedValue` | string, nullable | Yes | What the refused command carried, as a decimal string at the reason's own scale. Null when the reason states no pair. | | > `limitValue` | string, nullable | Yes | The bound it breached, in the same unit and at the same scale. | | > `unit` | string, nullable | Yes | What the pair measures — derived by this edge so the numbers are self-describing. Null whenever the pair is null. It is also null for `INVALID_FIELD` even when a pair is stated: that reason covers arms whose observed value is a price on one and a quantity on another, and the reason alone cannot say which, so no unit is claimed rather than one guessed. Treat a null `unit` beside a non-null pair as "unlabelled", never as a default unit. One of `PRICE`, `QTY`, `NOTIONAL`, `BPS`, `NS`, `COUNT`. | | > `tradingPolicyId` | integer, nullable | Yes | The policy in scope when the refusal fired; null when the refusing check ran before policy resolution. | | > `tradingPolicyVersion` | string, nullable | Yes | The policy's version as a decimal string; null when none resolved. | > An order's applied image (msgType orderUpdate)