WebSocket API — Orders Channel
Live order lifecycle events are encrypted end to end. The edge forwards ciphertext; the SDK decrypts the protobuf OrderUpdateMessage locally.
the WebSocket origin/ws/v1
Authenticate with op: login first (see WebSocket Trading).
Subscribe
{ "id": "c-2", "op": "subscribe", "args": { "channel": "orders" } }
Response:
{ "id": "c-2", "op": "subscribe", "code": 0, "data": { "channel": "orders", "seq_start": 1 } }
Event Flow
snapshot → snapshot → ... → snapshot (snapshot_complete: true) → update → update → ...
The server first replays every currently live order as a snapshot frame, then emits update frames as state changes. The final snapshot frame carries snapshot_complete: true; that is the signal to start applying buffered updates.
Incremental updates that arrive while snapshot delivery is in progress should be buffered and replayed after snapshot_complete: true.
Encrypted frame
Transport frames carry encrypted payload metadata rather than a plaintext order object. After SDK decryption, the payload has the schema below.
{
"encrypted": true,
"message_type": "ORDER_UPDATE",
"encrypted_body": "<base64 ciphertext>",
"nonce": 12,
"fencing_epoch": 7,
"correlation_id": "100"
}
| Field | Description |
|---|---|
| The SDK must authenticate/decrypt the body before interpreting any order values. |
Decrypted OrderUpdateMessage
message_type | Meaning |
|---|---|
ACK, OPEN, PARTIALLY_FILLED, FILLED | Acknowledgement and working/fill lifecycle |
CANCELLED, REJECTED | Terminal cancellation/rejection |
MODIFIED | Amend applied |
CANCEL_REJECTED, MODIFY_REJECTED | Requested operation rejected |
Field Reference
| Field | Type | Description |
|---|---|---|
message_type | string | See table above |
order_id, symbol_id, timestamp | u64 | Venue ids and event time |
account, correlation_id | bytes | Owner account (32-byte Solana identity, exposed as base58 by SDKs) and client correlation key |
side, order_type, order_status, message_type | enum | Uppercase SDK enum values |
price, quantity, filled_qty, remaining_qty, cum_fill | decimal string | Exact decimal values; do not parse as binary float |
avg_fill_price, realized_pnl, trading_fee | optional decimal string | Fill/accounting values |
leverage | u32 | Applied leverage |
cancel_reason, close_reason, tpsl_status | optional enum | Structured lifecycle reasons |
reject_reason_code | optional u32 | Product error code |
msg | optional string | Human-readable reject detail |
take_profit, stop_loss, trigger_price | optional decimal string | Trigger attributes |
peg_offset_bps | optional signed i32 | Original Pyth peg offset |
reduce_only, post_only | boolean | Placement attributes |
Rejection Reasons
Use reject_reason_code and the trade ACK/error-code catalog. msg is supplementary and must not be used as a stable programmatic enum.
Cancellation Reasons
Values for cancel_reason when message_type is cancelled:
| Value | Description |
|---|---|
USER_REQUESTED | User cancellation |
IOC_REMAINDER | Unfilled portion of an IOC order |
FOK_NOT_FILLED | FOK order could not fully fill |
EXPIRED | Reached expiry_time on a GTD order (ACK catalog: GTD_EXPIRED / 2026) |
SYSTEM | System cancellation |
ADL | Auto-deleveraging cancellation |
LIQUIDATED_CANCELED | Position liquidation cancelled the order |
MARGIN_CANCELED | Margin protection cancelled the order |
REDUCE_ONLY | Reduce-only constraints cancelled the remainder |
STP_EXPIRE_TAKER | Self-trade prevention expired the taker |
STP_CANCEL_RESTING | Self-trade prevention cancelled the resting order |
Gap Recovery
Clients should track seq. If a gap appears (seq_n > seq_{n-1} + 1):
op: unsubscribe{ channel: "orders" }op: subscribe{ channel: "orders" }— receive a fresh snapshot- Resume applying updates from the new
seqseries
Unsubscribe
{ "id": "c-9", "op": "unsubscribe", "args": { "channel": "orders" } }