Tutorial

Prerequisites

Before connecting to WebSocket, you need:

  • An authentication token. Obtain one via POST /auth/login or use an access key from GET /accesskeys.

  • Your customer ID (UUID). Obtained from your account or GET /customers.

  • (Optional) Agent IDs (UUIDs) for agent-level subscriptions. Obtained from GET /agents.

  • A WebSocket client library (e.g., websocket-client for Python, ws for Node.js, or the browser’s native WebSocket API).

Note

AI Implementation Hint

The WebSocket URL is wss://api.voipbin.net/v1.0/ws?token=<token>. Always use wss:// (not ws://) for production. The token is passed as a query parameter, not a header. After connecting, you must send a subscribe message before any events will be delivered. If the connection drops, all subscriptions are lost and must be re-sent after reconnecting.

Connect to WebSocket

Establish a WebSocket connection to receive real-time event updates from VoIPBIN. The WebSocket provides bi-directional communication for subscribing to specific event topics.

WebSocket Endpoint:

wss://api.voipbin.net/v1.0/ws?token=<YOUR_AUTH_TOKEN>

Subscribe to Events

After connecting, send a subscription message to receive events for specific resources.

Subscription Message Format:

{
    "type": "subscribe",
    "topics": [
        "customer_id:<your-customer-id>:call:<call-id>",
        "customer_id:<your-customer-id>:activeflow:<activeflow-id>",
        "agent_id:<your-agent-id>:queue:<queue-id>"
    ]
}

Example Subscription:

{
    "type": "subscribe",
    "topics": [
        "customer_id:12345678-1234-1234-1234-123456789012:call:*",
        "customer_id:12345678-1234-1234-1234-123456789012:message:*"
    ]
}

This subscribes to all call and message events for your customer account.

Unsubscribe from Events

Stop receiving events for specific topics by sending an unsubscribe message.

{
    "type": "unsubscribe",
    "topics": [
        "customer_id:12345678-1234-1234-1234-123456789012:call:*"
    ]
}

WebSocket Client Examples

Python Example:

Using the websocket-client library:

import websocket
import json
import time

def on_message(ws, message):
    """Handle incoming WebSocket messages"""
    data = json.loads(message)
    event_type = data.get('event_type')
    resource_data = data.get('data')

    print(f"Received event: {event_type}")

    if event_type == 'call.status':
        call_id = resource_data['id']
        status = resource_data['status']
        print(f"Call {call_id} status: {status}")

    elif event_type == 'message.received':
        message_text = resource_data['text']
        from_number = resource_data['source']['target']
        print(f"Message from {from_number}: {message_text}")

    elif event_type == 'activeflow.updated':
        activeflow_id = resource_data['id']
        current_action = resource_data['current_action']['type']
        print(f"Activeflow {activeflow_id} executing: {current_action}")

def on_error(ws, error):
    """Handle WebSocket errors"""
    print(f"Error: {error}")

def on_close(ws, close_status_code, close_msg):
    """Handle WebSocket connection close"""
    print(f"Connection closed: {close_status_code} - {close_msg}")

def on_open(ws):
    """Handle WebSocket connection open"""
    print("WebSocket connection established")

    # Subscribe to events after connection opens
    subscription = {
        "type": "subscribe",
        "topics": [
            "customer_id:12345678-1234-1234-1234-123456789012:call:*",
            "customer_id:12345678-1234-1234-1234-123456789012:message:*",
            "customer_id:12345678-1234-1234-1234-123456789012:activeflow:*"
        ]
    }
    ws.send(json.dumps(subscription))
    print("Subscribed to events")

if __name__ == "__main__":
    # Replace with your actual token
    token = "<YOUR_AUTH_TOKEN>"
    ws_url = f"wss://api.voipbin.net/v1.0/ws?token={token}"

    # Create WebSocket connection
    ws = websocket.WebSocketApp(
        ws_url,
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close
    )

    # Run forever (blocks)
    ws.run_forever()

JavaScript (Browser) Example:

const token = '<YOUR_AUTH_TOKEN>';
const wsUrl = `wss://api.voipbin.net/v1.0/ws?token=${token}`;

// Create WebSocket connection
const ws = new WebSocket(wsUrl);

ws.onopen = function(event) {
    console.log('WebSocket connection established');

    // Subscribe to events
    const subscription = {
        type: 'subscribe',
        topics: [
            'customer_id:12345678-1234-1234-1234-123456789012:call:*',
            'customer_id:12345678-1234-1234-1234-123456789012:message:*'
        ]
    };
    ws.send(JSON.stringify(subscription));
    console.log('Subscribed to events');
};

ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    const eventType = data.event_type;

    console.log(`Received event: ${eventType}`);

    switch(eventType) {
        case 'call.status':
            handleCallStatus(data.data);
            break;
        case 'message.received':
            handleMessageReceived(data.data);
            break;
        case 'activeflow.updated':
            handleActiveflowUpdate(data.data);
            break;
        default:
            console.log('Unknown event type:', eventType);
    }
};

ws.onerror = function(error) {
    console.error('WebSocket error:', error);
};

ws.onclose = function(event) {
    console.log('WebSocket connection closed:', event.code, event.reason);

    // Implement reconnection logic if needed
    setTimeout(function() {
        console.log('Reconnecting...');
        // Recreate connection
    }, 5000);
};

function handleCallStatus(callData) {
    console.log(`Call ${callData.id} status: ${callData.status}`);
    // Update UI
    document.getElementById('call-status').textContent = callData.status;
}

function handleMessageReceived(messageData) {
    console.log(`Message from ${messageData.source.target}: ${messageData.text}`);
    // Display message in UI
    const messageList = document.getElementById('messages');
    const messageElement = document.createElement('div');
    messageElement.textContent = `${messageData.source.target}: ${messageData.text}`;
    messageList.appendChild(messageElement);
}

function handleActiveflowUpdate(activeflowData) {
    console.log(`Activeflow ${activeflowData.id} action: ${activeflowData.current_action.type}`);
    // Update flow visualization
}

Node.js Example:

Using the ws library:

const WebSocket = require('ws');

const token = '<YOUR_AUTH_TOKEN>';
const wsUrl = `wss://api.voipbin.net/v1.0/ws?token=${token}`;

// Create WebSocket connection
const ws = new WebSocket(wsUrl);

ws.on('open', function() {
    console.log('WebSocket connection established');

    // Subscribe to events
    const subscription = {
        type: 'subscribe',
        topics: [
            'customer_id:12345678-1234-1234-1234-123456789012:call:*',
            'customer_id:12345678-1234-1234-1234-123456789012:message:*',
            'customer_id:12345678-1234-1234-1234-123456789012:queue:*'
        ]
    };
    ws.send(JSON.stringify(subscription));
    console.log('Subscribed to events');
});

ws.on('message', function(data) {
    const message = JSON.parse(data);
    const eventType = message.event_type;

    console.log(`Received event: ${eventType}`);

    // Process events
    switch(eventType) {
        case 'call.status':
            console.log(`Call ${message.data.id}: ${message.data.status}`);
            break;

        case 'queue.joined':
            console.log(`Caller ${message.data.call_id} joined queue ${message.data.queue_id}`);
            // Notify agents
            notifyAgents(message.data);
            break;

        case 'message.received':
            console.log(`Message: ${message.data.text}`);
            // Process message
            processIncomingMessage(message.data);
            break;
    }
});

ws.on('error', function(error) {
    console.error('WebSocket error:', error);
});

ws.on('close', function(code, reason) {
    console.log(`WebSocket closed: ${code} - ${reason}`);

    // Implement reconnection
    setTimeout(function() {
        console.log('Reconnecting...');
        // Recreate connection
    }, 5000);
});

function notifyAgents(queueData) {
    // Notify available agents about new call in queue
    console.log(`Notifying agents about queue entry`);
}

function processIncomingMessage(messageData) {
    // Auto-respond or route to agent
    console.log(`Processing message from ${messageData.source.target}`);
}

Topic Pattern Matching

WebSocket supports wildcard subscriptions using * to match multiple resources.

Subscribe to all calls:

{
    "type": "subscribe",
    "topics": [
        "customer_id:12345678-1234-1234-1234-123456789012:call:*"
    ]
}

Subscribe to specific call:

{
    "type": "subscribe",
    "topics": [
        "customer_id:12345678-1234-1234-1234-123456789012:call:a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    ]
}

Subscribe to multiple resource types:

{
    "type": "subscribe",
    "topics": [
        "customer_id:12345678-1234-1234-1234-123456789012:call:*",
        "customer_id:12345678-1234-1234-1234-123456789012:message:*",
        "customer_id:12345678-1234-1234-1234-123456789012:conference:*",
        "customer_id:12345678-1234-1234-1234-123456789012:queue:*"
    ]
}

Agent-level subscription:

{
    "type": "subscribe",
    "topics": [
        "agent_id:98765432-4321-4321-4321-210987654321:queue:*",
        "agent_id:98765432-4321-4321-4321-210987654321:call:*"
    ]
}

Permission Requirements

Customer-Level Topics:

To subscribe to customer-level topics, you need: - Admin permission, OR - Manager permission

customer_id:<customer-id>:<resource>:<resource-id>

Agent-Level Topics:

Only the owner of the agent can subscribe:

agent_id:<agent-id>:<resource>:<resource-id>

Event Message Format

All WebSocket events follow this structure:

{
    "event_type": "call.status",
    "timestamp": "2026-01-20T10:30:00.000000Z",
    "topic": "customer_id:12345678-1234-1234-1234-123456789012:call:a1b2c3d4",
    "data": {
        // Event-specific resource data
    }
}

Fields: - event_type: Type of event (e.g., call.status, message.received) - timestamp: When the event occurred (ISO 8601 in UTC) - topic: The topic that triggered this event - data: Resource-specific data (call, message, activeflow, etc.)

Common Use Cases

Real-Time Call Monitoring:

Monitor all active calls in real-time:

# Python example
def on_message(ws, message):
    data = json.loads(message)

    if data['event_type'] == 'call.status':
        call = data['data']

        if call['status'] == 'answered':
            print(f"Call {call['id']} answered - Duration tracking started")
            start_call_timer(call['id'])

        elif call['status'] == 'hangup':
            print(f"Call {call['id']} ended")
            stop_call_timer(call['id'])
            calculate_call_metrics(call)

Live Agent Dashboard:

Update agent status and queue information in real-time:

# JavaScript example
ws.onmessage = function(event) {
    const data = JSON.parse(event.data);

    if (data.event_type === 'queue.joined') {
        // Update queue count
        updateQueueCount(data.data.queue_id, '+1');
        // Show notification to agents
        notifyAgents(`New caller in queue`);
    }

    if (data.event_type === 'agent.status') {
        // Update agent availability display
        updateAgentStatus(data.data.agent_id, data.data.status);
    }
};

Flow Execution Visualization:

Visualize flow execution in real-time:

# Node.js example
ws.on('message', function(data) {
    const message = JSON.parse(data);

    if (message.event_type === 'activeflow.updated') {
        const activeflow = message.data;

        // Update flow diagram
        highlightCurrentAction(
            activeflow.flow_id,
            activeflow.current_action.id
        );

        // Log action execution
        console.log(`Flow ${activeflow.flow_id}: Executing ${activeflow.current_action.type}`);
    }
});

Auto-Reply to Messages:

Respond to messages immediately when received:

# Python example
def on_message(ws, message):
    data = json.loads(message)

    if data['event_type'] == 'message.received':
        msg = data['data']

        # Auto-reply logic
        if 'help' in msg['text'].lower():
            send_auto_reply(
                to=msg['source']['target'],
                text="Thanks for reaching out! Our team will respond soon. For urgent matters, please call us at +15551234567."
            )

Best Practices

1. Connection Management: - Implement automatic reconnection with exponential backoff - Handle connection drops gracefully - Monitor connection health with ping/pong

2. Subscription Management: - Subscribe only to events you need - Use wildcards (*) for broad monitoring - Unsubscribe from unused topics to reduce load

3. Error Handling: - Catch and log all WebSocket errors - Implement timeout handling - Validate incoming message format

4. Performance: - Process messages asynchronously if handling is time-consuming - Batch UI updates to avoid excessive rendering - Use message queues for high-volume scenarios

5. Security: - Always use WSS (WebSocket Secure) in production - Rotate authentication tokens regularly - Validate message sources

6. Testing: - Test reconnection logic thoroughly - Simulate connection failures - Verify subscription/unsubscription works correctly

Connection Lifecycle

1. Connect:

ws = new WebSocket('wss://api.voipbin.net/v1.0/ws?token=<YOUR_AUTH_TOKEN>');

2. Subscribe on Open:

ws.onopen = function() {
    ws.send(JSON.stringify({
        type: 'subscribe',
        topics: ['customer_id:<id>:call:*']
    }));
};

3. Handle Messages:

ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    // Process event
};

4. Handle Disconnection:

ws.onclose = function(event) {
    console.log('Disconnected');
    // Implement reconnection
    setTimeout(reconnect, 5000);
};

5. Graceful Shutdown:

// Unsubscribe before closing
ws.send(JSON.stringify({
    type: 'unsubscribe',
    topics: ['customer_id:<id>:call:*']
}));

// Close connection
ws.close();

For more details about WebSocket topics and event types, see WebSocket Overview.