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 fromGET /customersorGET /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 byevent_typeand 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
WebSocket Overview - Connection and topic concepts
WebSocket Tutorial - Implementation examples
Call Struct - Complete call data structure
Message Struct - Complete message data structure
Activeflow Struct - Complete activeflow data structure
Tutorial
Before connecting to WebSocket, you need:
An authentication token. Obtain one via
POST /auth/loginor use an access key fromGET /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-clientfor Python,wsfor Node.js, or the browser’s nativeWebSocketAPI).
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.