Websocket Messages
List of messages subscriptions that are available on the Websocket
Connectivity Model
Section titled “Connectivity Model”Authentication
Section titled “Authentication”During authentication, a client can obtain multiple short-lived auth tokens by calling the /api/3/zm/rest/auth/token endpoint. Each received token can then be used to establish a WebSocket connection:
wss://trade-uk.sandbox.zodiamarkets.com/zm/ws/ws-client?token=<token>&sessionId=<sessionId>sessionId is optional and names the session this connection joins. Supply it if you use autoSubscribe on orders; it is what makes an order outcome recoverable across a reconnect. Omit it otherwise. Full rules — format, refusal, and the effect of reconnecting under a live sessionId — are on Order Sessions and Recovery →.
Connection Isolation
Section titled “Connection Isolation”Each WebSocket connection for a given client is independent. Connections have their own price subscriptions and can send and receive order requests separately.
Key Points:
- Each connection maintains its own price subscriptions
- Quote IDs can be shared across connections (as long as they are not expired)
- A request’s response is returned to the connection that made it
- Exception — orders sent with
autoSubscribe: true. Their outcome belongs to the session, not the connection, so it can be delivered to a different connection of yours, or redelivered on a later one. It is never delivered to another counterparty.
WebSocket Session Behavior
Section titled “WebSocket Session Behavior”Key Concepts
Section titled “Key Concepts”| Concept | Behavior |
|---|---|
| Price subscriptions | Bound to the connection that created them. Lost on disconnect. |
| QuoteIDs | Remain valid after disconnect. Can be used from any authenticated connection while the quote is still active. |
| Order responses (default) | Delivered only to the connection that submitted the order. Lost if it disconnects first. |
Order responses (autoSubscribe: true) |
Delivered to the session. Redelivered on reconnect under the same sessionId until you send orderUnsubscribe. |
Connection Scenarios
Section titled “Connection Scenarios”The examples below use Connection A and Connection B to represent separate WebSocket connections from the same client. Each scenario states the result for both delivery models; where only one line is given, both behave the same way.
Scenario 1: Reconnection After Disconnect
Section titled “Scenario 1: Reconnection After Disconnect”Connection A: subscribe → receives quoteID, price stream activeConnection A: disconnectsConnection A: reconnectsResult:
- Price stream: Stopped. Client must re-subscribe.
- QuoteID: Still usable. Can be submitted on the new connection, if the quote remains active.
Scenario 2: Order Submitted on Different Connection
Section titled “Scenario 2: Order Submitted on Different Connection”Connection A: subscribe → receives quoteIDConnection B: connects, submits order using quoteID from Connection AResult:
- Default delivery: Delivered to Connection B only (the submitting connection).
autoSubscribe: true:PENDINGto Connection B; the terminal to whichever connection holds Connection B’s session when it arrives.
Scenario 3: Submitting Connection Disconnects Before Response
Section titled “Scenario 3: Submitting Connection Disconnects Before Response”Connection A: subscribe → receives quoteIDConnection B: submits order using quoteIDConnection B: disconnects before responseResult:
- Default delivery: Lost. Neither connection receives it. Recover it with Read Order State →, or by retrying the order with the same
idempotencyKey. autoSubscribe: true: Not lost. The outcome is recorded and delivered to the session — pushed live if another connection already holds thatsessionId, otherwise redelivered when you reconnect under it.
Scenario 4: Subscription Connection Disconnects After Order Submission
Section titled “Scenario 4: Subscription Connection Disconnects After Order Submission”Connection A: subscribe → receives quoteIDConnection B: submits order using quoteIDConnection A: disconnectsResult:
- Order response: Delivered to Connection B, under both delivery models.
Scenario 5: Reconnecting Under the Same Session
Section titled “Scenario 5: Reconnecting Under the Same Session”Connection A: connects with ?sessionId=desk-1, submits order with autoSubscribe: trueConnection A: receives PENDING, then disconnectsConnection B: connects with ?sessionId=desk-1Result:
- Order response: Delivered to Connection B — either pushed live if the terminal arrives while B is connected, or redelivered on connect if it was recorded while nobody held the session.
- Price stream: Stopped. Connection B must re-subscribe; price subscriptions are not part of a session.
- Had Connection A still been live, connecting B under the same
sessionIdwould have closed A.
Trade Subscription Types
Section titled “Trade Subscription Types”The following types of subscription methods are supported:
| Subscription Type | Description | Requirements | Details |
|---|---|---|---|
| Normal Price subscriptions | Execute trade using own funds and delivered to own account/wallet | Account With ZM with Authorized Traders access to RFS | Price Channel→ |
| Beneficiary Price Subscription | Execute trade using own funds but delivered to third party wallet address | Third Party Beneficiary registered with ZM with delivery wallet whitelisted and verified. | Beneficiary Price Channel→ |
| Sender Price Subscription | Execute trade using third party crypto funds but delivered to own account/wallet | Third Party Sender registered with ZM with collection (sending) wallet whitelisted and verified. | Sender Price Channel→ |
Best Practices
Section titled “Best Practices”Managing Multiple Connections
Section titled “Managing Multiple Connections”# Example: Managing multiple WebSocket connectionsclass WebSocketManager: def __init__(self): self.connections = {} self.subscriptions = {}
def add_connection(self, name, ws): """Add a new WebSocket connection""" self.connections[name] = ws self.subscriptions[name] = []
def subscribe(self, connection_name, instrument): """Subscribe to prices on specific connection""" ws = self.connections[connection_name] ws.send(json.dumps({ 'messageType': 'subscribe', 'instrument': instrument, ... })) self.subscriptions[connection_name].append(instrument)
def submit_order(self, connection_name, quote_id): """Submit order on specific connection""" ws = self.connections[connection_name] ws.send(json.dumps({ 'messageType': 'order', 'quoteId': quote_id, ... })) # Order response will come back on this connection
# Usagemanager = WebSocketManager()manager.add_connection('pricing', ws_connection_1)manager.add_connection('trading', ws_connection_2)
# Subscribe on pricing connectionmanager.subscribe('pricing', 'BTC.USD')
# Submit order on trading connection (can use quoteID from pricing)manager.submit_order('trading', quote_id_from_pricing_connection)Handling Disconnections
Section titled “Handling Disconnections”def handle_disconnect(connection_name): """Handle connection disconnect""" # Price subscriptions are lost subscriptions = self.subscriptions[connection_name]
# Reconnect new_ws = reconnect() self.connections[connection_name] = new_ws
# Re-subscribe to all previous subscriptions for instrument in subscriptions: self.subscribe(connection_name, instrument)
# Note: QuoteIDs from before disconnect are still valid # Can continue using them if quotes are still activeEnsuring Order Response Receipt
Section titled “Ensuring Order Response Receipt”def submit_order_safely(ws, quote_id): """Submit order and wait for response""" order_submitted = threading.Event() order_response = None
def on_message(msg): nonlocal order_response if msg['messageType'] == 'order': order_response = msg order_submitted.set()
# Submit order ws.send(json.dumps({ 'messageType': 'order', 'quoteId': quote_id, ... }))
# Wait for response (with timeout) if order_submitted.wait(timeout=10): return order_response else: # Timeout - order may still execute # Check order status via REST API return NoneImportant Reminders
Section titled “Important Reminders”- 🔄 Price subscriptions do not persist across disconnections - always re-subscribe after reconnecting
- 📌 Order subscriptions do persist. An order sent with
autoSubscribe: trueis redelivered on every reconnect under the samesessionIduntil you sendorderUnsubscribe - 🎫 Quote IDs remain valid even after the subscribing connection disconnects
- 📨 Order responses go to the submitting connection - not the connection that subscribed to prices. With
autoSubscribe: truethey go to the session instead, so correlate ontransactionId - ⚠️ Orders may execute even if the connection drops before receiving a response - recover the outcome, never re-place the order