A WebSocket connection is provided to stream brokerage prices as executable quotes through our Request-For-Stream (RFS) service
WebSocket API - RFS (Request for Stream)
The WebSocket API provides real-time streaming prices and instant order execution through Zodia Markets' Request for Stream (RFS) service. Unlike REST API's request-response pattern, WebSocket maintains a persistent connection for continuous price updates.
What You Can Do
With the WebSocket API, you can:
- Stream live prices for multiple currency pairs simultaneously
- Execute trades instantly on displayed prices
- Subscribe/unsubscribe to price streams dynamically
- Specify beneficiary on subscription For quotes on delivering crypto to third party wallets
Environment URLs
Connect to the appropriate environment for your integration stage:
Sandbox:
wss://trade-uk.sandbox.zodiamarkets.comProduction:
wss://trade-uk.zodiamarkets.com
Note on EntitiesURLs shown are for the UK entity. If you're onboarded with the AME entity, replace
trade-ukwithtrade-amein the URLs above.
Authentication Overview
WebSocket connections require token-based authentication:
Step 1: Obtain WebSocket Token
First, request a WebSocket authentication token via REST API:
token_response = make_api_request('POST', 'api/3/zm/rest/auth/token', {})
ws_token = token_response['token']const tokenResponse = await makeApiRequest('POST', 'api/3/zm/rest/auth/token', {});
const wsToken = tokenResponse.token;The token is valid for a limited time (typically 1 hour).
Step 2: Connect with Token
Use the token to establish your WebSocket connection.
wss://trade-uk.zodiamarkets.com/zm/ws/ws-client?token={token}Service Availability
Trading Hours
The RFS WebSocket service operates during:
Monday to Friday: 04:00 GMT to 22:00 GMT, including public holidays
For trading outside these hours, contact the Zodia Markets OTC Brokerage desk:
Maintenance Windows
Scheduled maintenance is announced in advance on the Status Page. Typical maintenance windows:
- Daily: 21:00 GMT - 21:15 GMT
Connection Lifecycle
1. Obtain Token (REST API)
↓
2. Connect to WebSocket
↓
3. Authenticate with Token
↓
4. Subscribe to Price Streams
↓
5. Receive Price Updates
↓
6. Execute Orders (Optional)
↓
7. Disconnect or Token ExpiresConnection Best Practices
Handling Disconnections
WebSocket connections can disconnect for various reasons. Implement automatic reconnection:
import time
def connect_with_retry(ws_url, max_retries=5):
"""Connect with exponential backoff retry"""
for attempt in range(max_retries):
try:
# Get fresh token
token_response = make_api_request('POST', 'api/3/zm/rest/auth/token', {})
ws_token = token_response['token']
# Connect and authenticate
ws = create_connection(ws_url)
authenticate(ws, ws_token)
return ws
except Exception as e:
if attempt < max_retries - 1:
wait_time = 2 ** attempt
print(f"Connection failed. Retrying in {wait_time}s...")
time.sleep(wait_time)
else:
raiseasync function connectWithRetry(wsUrl, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
// Get fresh token
const tokenResponse = await makeApiRequest('POST', 'api/3/zm/rest/auth/token', {});
const wsToken = tokenResponse.token;
// Connect and authenticate
return new Promise((resolve, reject) => {
const ws = new WebSocket(wsUrl);
ws.on('open', () => {
authenticate(ws, wsToken);
resolve(ws);
});
ws.on('error', reject);
});
} catch (error) {
if (attempt < maxRetries - 1) {
const waitTime = Math.pow(2, attempt) * 1000;
console.log(`Connection failed. Retrying in ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} else {
throw error;
}
}
}
}Token Expiry Handling
WebSocket tokens expire after a set period. Monitor for expiry and refresh:
def monitor_connection(ws):
"""Monitor connection and handle token expiry"""
while True:
try:
message = json.loads(ws.recv())
if message.get('error') == 'expired token':
print("Token expired. Reconnecting...")
ws.close()
ws = connect_with_retry(ws_url)
resubscribe_to_streams(ws)
else:
handle_message(message)
except Exception as e:
print(f"Connection error: {e}")
ws = connect_with_retry(ws_url)
resubscribe_to_streams(ws)function monitorConnection(ws) {
ws.on('message', async (data) => {
const message = JSON.parse(data);
if (message.error === 'expired token') {
console.log('Token expired. Reconnecting...');
ws.close();
ws = await connectWithRetry(wsUrl);
resubscribeToStreams(ws);
} else {
handleMessage(message);
}
});
ws.on('close', async () => {
console.log('Connection closed. Reconnecting...');
ws = await connectWithRetry(wsUrl);
resubscribeToStreams(ws);
});
}