Websocket

Overview

WebSocket, a powerful feature within VoIPBIN, revolutionizes web applications by enabling them to subscribe to specific event topics. This capability facilitates real-time updates, ensuring dynamic data changes are seamlessly communicated during runtime.

WebSocket establishes a persistent and bi-directional connection with the VoIPBIN server, providing web applications with real-time capabilities for constructing dynamic and interactive communication applications.

Websocket endpoint

To leverage WebSocket in VoIPBIN, connect to the following endpoint:

GET wss://api.voipbin.net/v1.0/ws?token=<your authtoken here>

Topic Subscription/Unsubscription

WebSocket functionality empowers users to finely tune their event subscriptions in the VoIPBIN system, tailoring updates to match their application’s specific resource needs. This section outlines the process for subscribing or unsubscribing from event topics.

To initiate a subscription or unsubscription, send the following JSON message through the established WebSocket:

{
    "type": "<subscribe|unsubscribe>",
    "topics": ["<topic>", ...]
}

The topic format is as follows:

agent_id:<agent_id>:<resource>:<resource-id>
customer_id:<customer_id>:<resource>:<resource-id>

Here’s an example of a subscribe message:

{
    "type": "subscribe",
    "topics": [
        "customer_id:5013bc52-da9a-11ee-844f-2fa34248de28:activeflow:74ac5405-7c70-4184-9388-1c9f8f8ce25f"
    ]
}

Subscribing to the topic activeflow:74ac5405-7c70-4184-9388-1c9f8f8ce25f ensures reception of events related to the specified activeflow resource with the provided ID.

It is crucial to adhere to the correct topic structure, including the following prefixes:

  • agent_id:<agent-id>

  • customer_id:<customer-id>

Additionally, specific permissions are required for different levels of topics:

Customer Level Topics

To subscribe to topics at the customer level, the following permissions are required:

  • Admin permission

  • Manager permission

Agent Level Topics

For agent-level topics, only the owner of the agent can subscribe to the topic.

Ensure the accuracy of your topic definition to successfully subscribe to the desired events.

Pattern Matching Subscription

WebSocket supports pattern matching subscriptions, allowing users to subscribe to multiple topics based on a pattern. For example, subscribing to the <resource> topic encompasses all events related to a specific resource type.

This pattern matching approach streamlines and enhances topic subscriptions, enabling users to receive updates for multiple resources without the need for individual subscriptions.

Real-Time Event Updates

When an event transpires for a subscribed topic, VoIPBIN dispatches the corresponding event data to the WebSocket connection. Web applications receive this data in real-time, facilitating immediate updates and dynamic data changes within the application.

Web applications can seamlessly process these event updates to trigger actions, update UI elements, or reflect changes in the user interface without resorting to manual page refreshes. WebSocket ensures a seamless and interactive user experience, keeping users consistently informed with the latest information.

Benefits of WebSocket

WebSocket extends various benefits to web applications leveraging VoIPBIN:

  • Real-Time Communication: WebSocket fosters instant updates and event notifications, establishing real-time communication between the web application and the VoIPBIN server.

  • Dynamic Data Updates: WebSocket facilitates the handling of dynamic data changes, enabling the creation of dynamic and interactive user interfaces.

  • Efficient Subscription: Pattern matching subscription efficiency allows users to subscribe to multiple resources without the need for individual subscriptions.

  • Reduced Latency: By eliminating the need for repeated HTTP requests, WebSocket reduces latency, enhancing the overall responsiveness of the application.

Struct

Subscribe

{
    "type": "unsubscribe",
    "topics": [...]
}
  • topic: List of subscribe topics.

Example

{
    "type": "subscribe",
    "topics": ["call"]
}

Unsubscribe

{
    "type": "unsubscribe",
    "topics": [...]
}
  • topic: List of unsubscribe topics.

Example

{
    "type": "subscribe",
    "topics": ["call"]
}

Tutorial

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.