Websocket

Stream real-time events from VoIPBIN services over a persistent WebSocket connection for low-latency updates.

API Reference: Websocket endpoints

Overview

Note

AI Context

  • Complexity: Medium – Requires persistent connection management, topic subscription, and reconnection logic.

  • Cost: Free – WebSocket connections and event delivery do not incur charges.

  • Async: Yes. Connect via wss://api.voipbin.net/v1.0/ws?token=<token>, then send subscribe messages to receive events. Events are pushed asynchronously as they occur on subscribed topics.

VoIPBIN’s WebSocket API enables real-time, bi-directional communication for receiving instant event notifications. WebSockets maintain persistent connections, allowing immediate delivery of call status changes, message arrivals, flow updates, and other platform events without polling.

The WebSocket API provides:

  • Real-time event streaming for calls, messages, and flows

  • Topic-based subscription filtering

  • Bi-directional communication channel

  • Low-latency event delivery

  • Wildcard pattern matching for subscriptions

How WebSocket Works

WebSocket maintains a persistent connection for instant event delivery.

WebSocket Architecture

+-----------------------------------------------------------------------+
|                       WebSocket System                                |
+-----------------------------------------------------------------------+

Client                          VoIPBIN                        Services
   |                               |                               |
   | 1. WSS Connection             |                               |
   +------------------------------>|                               |
   |                               |                               |
   |   2. Connection Accepted      |                               |
   |<------------------------------+                               |
   |                               |                               |
   | 3. Subscribe to topics        |                               |
   +------------------------------>|                               |
   |                               |                               |
   |   4. Subscription confirmed   |                               |
   |<------------------------------+                               |
   |                               |                               |
   |                               |        5. Event occurs        |
   |                               |<------------------------------+
   |                               |                               |
   |   6. Event delivered          |                               |
   |<------------------------------+                               |
   |                               |                               |

Continuous Connection:
+-----------------------------------------------------------------------+
| Unlike HTTP (request-response), WebSocket maintains an open channel   |
| Events are pushed instantly as they occur - no polling needed         |
+-----------------------------------------------------------------------+

Note

AI Implementation Hint

The topic format is <scope>:<scope_id>:<resource>:<resource_id>. Use * as the resource_id to subscribe to all resources of a type (e.g., customer_id:abc123:call:* for all call events). Always implement automatic reconnection with exponential backoff since connections can drop due to network issues or token expiration.

Key Components

  • WebSocket Connection: Persistent bi-directional channel

  • Topics: Event filters for specific resources

  • Subscriptions: Active topic registrations

  • Events: Real-time notifications pushed to clients

Connection Architecture

WebSocket connections integrate with VoIPBIN’s event system.

Event Flow Architecture

+-----------------------------------------------------------------------+
|                    WebSocket Event Pipeline                           |
+-----------------------------------------------------------------------+

+-------------------+     +-------------------+     +-------------------+
|   VoIPBIN         |     |   Event           |     |   WebSocket       |
|   Services        |---->|   Router          |---->|   Handler         |
+-------------------+     +-------------------+     +-------------------+
                                  |
                                  | Route by topic
                                  v
                          +-------+-------+
                          |               |
                          v               v
                +-------------+   +-------------+
                | Client A    |   | Client B    |
                | Topics:     |   | Topics:     |
                | - call:*    |   | - msg:*     |
                | - queue:*   |   | - flow:*    |
                +-------------+   +-------------+

Event Publishing:
+-----------------------------------------------------------------------+
| 1. Service generates event (call answered, message received, etc.)    |
| 2. Event router matches topic patterns                                 |
| 3. Event pushed to all subscribed clients                             |
+-----------------------------------------------------------------------+

Topic System

Topics define which events a client receives.

Topic Format

+-----------------------------------------------------------------------+
|                         Topic Structure                               |
+-----------------------------------------------------------------------+

Format: <scope>:<scope_id>:<resource>:<resource_id>

Examples:
+-----------------------------------------------------------------------+
| customer_id:abc123:call:*           | All calls for customer          |
| customer_id:abc123:call:xyz789      | Specific call                   |
| customer_id:abc123:message:*        | All messages for customer       |
| agent_id:agent123:queue:*           | All queues for agent            |
+-----------------------------------------------------------------------+

Wildcard (*):
+-----------------------------------------------------------------------+
| Use * to match all resources of a type                                |
| customer_id:abc123:call:*  -> All call events                        |
| customer_id:abc123:*:*     -> All events (not recommended)           |
+-----------------------------------------------------------------------+

Available Resource Types

Resource

Description

call

Call status changes, connection, hangup

message

SMS/MMS received, sent, delivery status

activeflow

Flow execution updates, action changes

conference

Conference events, participant join/leave

queue

Queue entry, exit, agent assignment

agent

Agent status changes

recording

Recording start, stop, completion

transcription

Transcription results

Connection Lifecycle

WebSocket connections follow a defined lifecycle.

Connection States

+-------------------+
|   Disconnected    |
+--------+----------+
         |
         | WSS Connect with token
         v
+-------------------+
|   Connecting      |
+--------+----------+
         |
         | Token validated
         v
+-------------------+     Subscribe
|   Connected       |<-------------------+
+--------+----------+                    |
         |                               |
         | Send subscription             |
         v                               |
+-------------------+     Unsubscribe    |
|   Subscribed      +--------------------+
+--------+----------+
         |
         | Connection lost / Close
         v
+-------------------+
|   Disconnected    |
+-------------------+
         |
         | Reconnect with backoff
         v
+-------------------+
|   Reconnecting    |
+-------------------+

Connection Endpoint

WebSocket URL:
+-----------------------------------------------------------------------+
| wss://api.voipbin.net/v1.0/ws?token=<YOUR_AUTH_TOKEN>                |
+-----------------------------------------------------------------------+

Authentication:
+-----------------------------------------------------------------------+
| Token passed as query parameter                                       |
| Same JWT or AccessKey token used for REST API                        |
+-----------------------------------------------------------------------+

Event Message Format

All events follow a consistent structure.

Event Structure

{
    "event_type": "call.status",
    "timestamp": "2024-01-15T10:30:00.000000Z",
    "topic": "customer_id:abc123:call:xyz789",
    "data": {
        // Resource-specific payload
    }
}

Common Event Types

Event Type

Description

call.status

Call state changed (ringing, answered, hangup)

call.created

New call initiated

message.received

Incoming SMS/MMS received

message.sent

Outgoing message sent

message.delivery

Message delivery status update

activeflow.updated

Flow action executed

activeflow.completed

Flow execution completed

conference.joined

Participant joined conference

conference.left

Participant left conference

queue.joined

Call entered queue

queue.connected

Call connected to agent

agent.status

Agent availability changed

recording.completed

Recording finished and available

Common Scenarios

Scenario 1: Real-Time Call Dashboard

Build a live dashboard showing all active calls.

Setup:
+--------------------------------------------+
| Subscribe to: customer_id:<id>:call:*      |
|                                            |
| Events received:                           |
| - call.created  -> Add to active list      |
| - call.status   -> Update call state       |
| - call.ended    -> Remove from list        |
+--------------------------------------------+

Dashboard Updates:
+--------------------------------------------+
| Incoming Call  |  +1-555-1234  |  Ringing  |
| Active Call    |  +1-555-5678  |  Answered |
| In Queue       |  +1-555-9012  |  Waiting  |
+--------------------------------------------+

Benefits:
+--------------------------------------------+
| - Instant visibility into call status      |
| - No polling required                      |
| - Real-time metrics and KPIs               |
+--------------------------------------------+

Scenario 2: Agent Desktop Application

Power a contact center agent interface.

Subscriptions:
+--------------------------------------------+
| agent_id:<agent-id>:queue:*                |
| agent_id:<agent-id>:call:*                 |
| customer_id:<cust-id>:message:*            |
+--------------------------------------------+

Event Handling:
+--------------------------------------------+
| queue.joined     -> Show notification       |
|                    "New caller waiting"     |
|                                            |
| call.assigned    -> Pop customer info      |
|                    Show call controls       |
|                                            |
| message.received -> Display in chat panel  |
|                    Enable quick reply       |
+--------------------------------------------+

Agent Interface:
+--------------------------------------------+
| [New Call Alert]      [Customer: John D.]  |
| Queue: Sales          Previous: 3 calls    |
| Wait time: 45s        Last purchase: $299  |
|                                            |
| [Accept Call] [Transfer] [Send to VM]     |
+--------------------------------------------+

Scenario 3: Message Auto-Response System

Automatically respond to incoming messages.

Subscription:
+--------------------------------------------+
| customer_id:<id>:message:*                 |
+--------------------------------------------+

Event Processing:
+--------------------------------------------+
| 1. Receive message.received event          |
| 2. Analyze message content                 |
| 3. Match against response rules            |
| 4. Send appropriate auto-reply             |
+--------------------------------------------+

Example Flow:
+--------------------------------------------+
| Incoming: "What are your hours?"           |
|                                            |
| -> Match keyword: "hours"                  |
| -> Auto-reply: "We're open Mon-Fri 9-5!"  |
|                                            |
| Incoming: "STOP"                           |
|                                            |
| -> Match keyword: "STOP"                   |
| -> Unsubscribe user from messages          |
| -> Confirm: "You've been unsubscribed"    |
+--------------------------------------------+

Best Practices

1. Connection Management

  • Implement automatic reconnection with exponential backoff

  • Start with 1 second delay, double on each failure (max 30 seconds)

  • Monitor connection health with ping/pong messages

  • Handle network transitions gracefully (WiFi to cellular)

2. Subscription Strategy

  • Subscribe only to events your application needs

  • Use specific resource IDs when possible (not just wildcards)

  • Unsubscribe when events are no longer needed

  • Resubscribe after reconnection

3. Error Handling

  • Handle connection errors gracefully

  • Parse messages safely with try/catch

  • Log all errors for debugging

  • Implement timeout handling for stale connections

4. Performance Optimization

  • Process events asynchronously for heavy operations

  • Batch UI updates to avoid excessive re-rendering

  • Use message queues for high-volume scenarios

  • Avoid blocking operations in event handlers

Troubleshooting

Connection Issues

Symptom

Solution

Connection refused

Verify token is valid; check endpoint URL; ensure WSS (not WS) for production

Connection drops

Implement reconnection logic; check network; verify token hasn’t expired

Authentication failure

Token may be expired; regenerate token; verify token has WebSocket permissions

Subscription Issues

Symptom

Solution

Not receiving events

Verify topic format is correct; check subscription was acknowledged; confirm events are actually occurring

Receiving wrong events

Review topic patterns; avoid overly broad wildcards; check customer_id is correct

Permission denied

Verify user has access to the resource; check agent_id matches token owner

Message Issues

Symptom

Solution

Malformed messages

Validate JSON parsing; handle unexpected fields gracefully; log raw messages

Missing event data

Check event_type for proper handling; verify data field exists before access

Delayed events

Check client processing time; verify network latency; monitor server health

Structures

This section documents the message structures used in VoIPBIN’s WebSocket API for subscription management and event delivery.

Message Overview

WebSocket communication uses JSON messages for all operations.

Message Categories

+-----------------------------------------------------------------------+
|                    WebSocket Message Types                            |
+-----------------------------------------------------------------------+

Client -> Server:
+-----------------------------------------------------------------------+
| subscribe     | Register for event notifications                      |
| unsubscribe   | Stop receiving event notifications                    |
+-----------------------------------------------------------------------+

Server -> Client:
+-----------------------------------------------------------------------+
| event         | Real-time event notification with resource data       |
| ack           | Acknowledgment of subscription changes                |
| error         | Error message for failed operations                   |
+-----------------------------------------------------------------------+

Subscribe Message

Send a subscribe message to receive events for specific topics.

Structure

{
    "type": "subscribe",
    "topics": [
        "<topic-pattern-1>",
        "<topic-pattern-2>",
        ...
    ]
}

Fields

  • type (enum string): Must be "subscribe".

  • topics (Array of String): List of topic patterns to subscribe to. Each topic follows the format <scope>:<scope_id>:<resource_type>:<resource_id>. Use * for the resource_id to match all resources of a type.

Example: Subscribe to all calls

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

Example: 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:activeflow:*"
    ]
}

Example: Subscribe to specific resource

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

Example: Agent-level subscription

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

Unsubscribe Message

Send an unsubscribe message to stop receiving events for specific topics.

Structure

{
    "type": "unsubscribe",
    "topics": [
        "<topic-pattern-1>",
        "<topic-pattern-2>",
        ...
    ]
}

Fields

  • type (enum string): Must be "unsubscribe".

  • topics (Array of String): List of topic patterns to unsubscribe from. Must match the exact topic patterns used during subscription.

Example: Unsubscribe from calls

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

Example: Unsubscribe from specific resource

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

Topic Pattern Structure

Topics follow a consistent format for event filtering.

Topic Format

<scope>:<scope_id>:<resource_type>:<resource_id>

Topic Components

  • scope (enum string): Access level. Either "customer_id" or "agent_id".

  • scope_id (UUID): The UUID of the customer or agent. Obtained from GET /customers or GET /agents.

  • resource_type (enum string): Type of resource: call, message, activeflow, conference, queue, agent, recording, transcription.

  • resource_id (UUID or *): UUID of a specific resource, or * to match all resources of the given type.

Valid Scopes

Scope

Permission Required

customer_id

Admin or Manager permission for the customer

agent_id

Must be the owner of the agent

Valid Resource Types

Resource Type

Events

call

call.created, call.status, call.ended

message

message.received, message.sent, message.delivery

activeflow

activeflow.updated, activeflow.completed

conference

conference.joined, conference.left, conference.ended

queue

queue.joined, queue.connected, queue.left

agent

agent.status

recording

recording.started, recording.completed

transcription

transcription.completed

Wildcard Usage

+-----------------------------------------------------------------------+
|                         Wildcard Patterns                             |
+-----------------------------------------------------------------------+

Specific resource:
customer_id:abc123:call:xyz789
-> Only events for call xyz789

All resources of type:
customer_id:abc123:call:*
-> All call events for customer abc123

Multiple types (separate subscriptions):
customer_id:abc123:call:*
customer_id:abc123:message:*
-> All calls AND all messages

Event Message Structure

Events are pushed from the server when subscribed resources change.

Structure

{
    "event_type": "<event-type>",
    "timestamp": "<ISO-8601-timestamp>",
    "topic": "<topic-that-matched>",
    "data": {
        // Resource-specific payload
    }
}

Fields

  • event_type (enum string): Type of event (e.g., "call.status", "message.received"). See WebSocket Overview for the full list.

  • timestamp (string, ISO 8601): When the event occurred, in UTC format.

  • topic (String): The topic pattern that triggered this event. Matches one of your subscribed topic patterns.

  • data (Object): Resource-specific data payload. Structure varies by event_type and corresponds to the relevant resource struct (e.g., Call for call events).

Note

AI Implementation Hint

Use the event_type field (not type) to determine the event kind for server-pushed events. The type field is used only for client-to-server messages (subscribe/unsubscribe) and server acknowledgments (ack/error). Always check for both type and event_type in your message handler to handle all message categories.

Event Type Reference

Complete list of event types and their data structures.

Call Events

// call.created
{
    "event_type": "call.created",
    "timestamp": "2024-01-15T10:30:00.000000Z",
    "topic": "customer_id:abc123:call:xyz789",
    "data": {
        "id": "xyz789",
        "customer_id": "abc123",
        "direction": "inbound",
        "source": {
            "type": "tel",
            "target": "+15551234567"
        },
        "destination": {
            "type": "tel",
            "target": "+15559876543"
        },
        "status": "ringing",
        "tm_create": "2024-01-15T10:30:00.000000Z"
    }
}

// call.status
{
    "event_type": "call.status",
    "timestamp": "2024-01-15T10:30:05.000000Z",
    "topic": "customer_id:abc123:call:xyz789",
    "data": {
        "id": "xyz789",
        "status": "answered",
        "previous_status": "ringing",
        "tm_update": "2024-01-15T10:30:05.000000Z"
    }
}

Message Events

// message.received
{
    "event_type": "message.received",
    "timestamp": "2024-01-15T10:30:00.000000Z",
    "topic": "customer_id:abc123:message:msg789",
    "data": {
        "id": "msg789",
        "customer_id": "abc123",
        "direction": "inbound",
        "source": {
            "type": "tel",
            "target": "+15551234567"
        },
        "destination": {
            "type": "tel",
            "target": "+15559876543"
        },
        "text": "Hello, I need help with my order",
        "tm_create": "2024-01-15T10:30:00.000000Z"
    }
}

// message.delivery
{
    "event_type": "message.delivery",
    "timestamp": "2024-01-15T10:30:02.000000Z",
    "topic": "customer_id:abc123:message:msg789",
    "data": {
        "id": "msg789",
        "status": "delivered",
        "tm_update": "2024-01-15T10:30:02.000000Z"
    }
}

Activeflow Events

// activeflow.updated
{
    "event_type": "activeflow.updated",
    "timestamp": "2024-01-15T10:30:00.000000Z",
    "topic": "customer_id:abc123:activeflow:flow789",
    "data": {
        "id": "flow789",
        "flow_id": "template123",
        "status": "executing",
        "current_action": {
            "id": "action456",
            "type": "play",
            "name": "welcome_message"
        },
        "tm_update": "2024-01-15T10:30:00.000000Z"
    }
}

// activeflow.completed
{
    "event_type": "activeflow.completed",
    "timestamp": "2024-01-15T10:35:00.000000Z",
    "topic": "customer_id:abc123:activeflow:flow789",
    "data": {
        "id": "flow789",
        "flow_id": "template123",
        "status": "completed",
        "result": "success",
        "tm_end": "2024-01-15T10:35:00.000000Z"
    }
}

Queue Events

// queue.joined
{
    "event_type": "queue.joined",
    "timestamp": "2024-01-15T10:30:00.000000Z",
    "topic": "customer_id:abc123:queue:queue789",
    "data": {
        "queue_id": "queue789",
        "call_id": "call456",
        "position": 3,
        "estimated_wait": 120,
        "tm_join": "2024-01-15T10:30:00.000000Z"
    }
}

// queue.connected
{
    "event_type": "queue.connected",
    "timestamp": "2024-01-15T10:32:00.000000Z",
    "topic": "customer_id:abc123:queue:queue789",
    "data": {
        "queue_id": "queue789",
        "call_id": "call456",
        "agent_id": "agent123",
        "wait_time": 120,
        "tm_connect": "2024-01-15T10:32:00.000000Z"
    }
}

Conference Events

// conference.joined
{
    "event_type": "conference.joined",
    "timestamp": "2024-01-15T10:30:00.000000Z",
    "topic": "customer_id:abc123:conference:conf789",
    "data": {
        "conference_id": "conf789",
        "call_id": "call456",
        "participant_count": 3,
        "tm_join": "2024-01-15T10:30:00.000000Z"
    }
}

// conference.left
{
    "event_type": "conference.left",
    "timestamp": "2024-01-15T10:45:00.000000Z",
    "topic": "customer_id:abc123:conference:conf789",
    "data": {
        "conference_id": "conf789",
        "call_id": "call456",
        "participant_count": 2,
        "reason": "hangup",
        "tm_leave": "2024-01-15T10:45:00.000000Z"
    }
}

Agent Events

// agent.status
{
    "event_type": "agent.status",
    "timestamp": "2024-01-15T10:30:00.000000Z",
    "topic": "agent_id:agent123:agent:agent123",
    "data": {
        "agent_id": "agent123",
        "status": "available",
        "previous_status": "busy",
        "tm_update": "2024-01-15T10:30:00.000000Z"
    }
}

Recording Events

// recording.completed
{
    "event_type": "recording.completed",
    "timestamp": "2024-01-15T10:45:00.000000Z",
    "topic": "customer_id:abc123:recording:rec789",
    "data": {
        "id": "rec789",
        "call_id": "call456",
        "duration": 300,
        "format": "wav",
        "size": 2400000,
        "reference_url": "https://storage.voipbin.net/recordings/rec789.wav",
        "tm_complete": "2024-01-15T10:45:00.000000Z"
    }
}

Acknowledgment Messages

Server may send acknowledgments for subscription operations.

Success Acknowledgment

{
    "type": "ack",
    "action": "subscribe",
    "topics": [
        "customer_id:abc123:call:*"
    ],
    "status": "success"
}

Error Response

{
    "type": "error",
    "action": "subscribe",
    "topics": [
        "customer_id:abc123:call:*"
    ],
    "code": "PERMISSION_DENIED",
    "message": "You do not have permission to subscribe to this topic"
}

Error Codes

Code

Description

PERMISSION_DENIED

User lacks permission for the topic

INVALID_TOPIC

Topic format is invalid

INVALID_MESSAGE

Message structure is invalid

RATE_LIMITED

Too many subscription requests

Message Handling Examples

Code examples for processing WebSocket messages.

JavaScript

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

    switch(message.type || message.event_type) {
        case 'ack':
            console.log('Subscription confirmed:', message.topics);
            break;

        case 'error':
            console.error('Error:', message.code, message.message);
            break;

        case 'call.status':
            handleCallStatus(message.data);
            break;

        case 'message.received':
            handleMessage(message.data);
            break;

        default:
            console.log('Received:', message.event_type, message.data);
    }
};

Python

def on_message(ws, raw_message):
    message = json.loads(raw_message)

    msg_type = message.get('type') or message.get('event_type')

    if msg_type == 'ack':
        print(f"Subscription confirmed: {message['topics']}")

    elif msg_type == 'error':
        print(f"Error: {message['code']} - {message['message']}")

    elif msg_type == 'call.status':
        handle_call_status(message['data'])

    elif msg_type == 'message.received':
        handle_message(message['data'])

    else:
        print(f"Received: {msg_type}")

Related Documentation

Tutorial

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.