List of messages subscriptions that are available on the Websocket
Connectivity Model
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>
Connection Isolation
Each WebSocket connection for a given client is fully independent. Connections have their own subscriptions and can send and receive order requests separately.
Key Points:
- Messages are not duplicated across a user's active connections
- Only the WebSocket connection that initiated a given request will receive the corresponding response
- Each connection maintains its own price subscriptions
- Quote IDs can be shared across connections (as long as they are not expired)
WebSocket Session Behavior
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 | Delivered only to the connection that submitted the order. |
Connection Scenarios
The examples below use Connection A and Connection B to represent separate WebSocket connections from the same client.
Scenario 1: Reconnection After Disconnect
Connection A: subscribe → receives quoteID, price stream active
Connection A: disconnects
Connection A: reconnects
Result:
- 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
Connection A: subscribe → receives quoteID
Connection B: connects, submits order using quoteID from Connection A
Result:
- Order response: Delivered to Connection B only (the submitting connection).
Scenario 3: Submitting Connection Disconnects Before Response
Connection A: subscribe → receives quoteID
Connection B: submits order using quoteID
Connection B: disconnects before response
Result:
- Order response: Lost. Neither connection receives it.
WarningThe order may still be executed. Ensure your connection remains stable until you receive the order response or subscribe to transaction endpoint or webhook to check transaction has been created
Scenario 4: Subscription Connection Disconnects After Order Submission
Connection A: subscribe → receives quoteID
Connection B: submits order using quoteID
Connection A: disconnects
Result:
- Order response: Delivered to Connection B.
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
Managing Multiple Connections
# Example: Managing multiple WebSocket connections
class 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
# Usage
manager = WebSocketManager()
manager.add_connection('pricing', ws_connection_1)
manager.add_connection('trading', ws_connection_2)
# Subscribe on pricing connection
manager.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
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
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
- 🔄 Subscriptions do not persist across disconnections - always re-subscribe after reconnecting
- 🎫 Quote IDs remain valid even after the subscribing connection disconnects
- 📨 Order responses go to the submitting connection - not the connection that subscribed to prices
- ⚠️ Orders may execute even if the connection drops before receiving a response