WebSocket

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.com

Production:

wss://trade-uk.zodiamarkets.com
📘

Note on Entities

URLs shown are for the UK entity. If you're onboarded with the AME entity, replace trade-uk with trade-ame in 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 Expires


Connection 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:
                raise
async 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);
    });
}