The WebSocket transport connects VoxCore to the iCallMate telephony dialler. Calls arrive as WebSocket connections carrying audio and control events in a custom JSON protocol.

Connection flow

Endpoint

WebSocket /ws/{bot_id}
bot_id identifies which bot configuration to fetch from VoxBridge.

Audio format

PropertyValue
EncodingLINEAR16 (signed 16-bit PCM)
Sample rate8,000 Hz
ChannelsMono
Transport encodingBase64 in JSON payload field

Handshake events

The dialler sends exactly three events after connection:
First event. Contains caller metadata.
FieldTypeDescription
eventstring"connected"
callerIdstringCaller’s phone number
didstringDialled number (DID)
callDirectionstring"incoming" or "outgoing"
streamIdstringStream identifier (optional, may come in start)
All fields from the connected event (minus event) are forwarded to VoxBridge as connected_event query params during config fetch.
Second event. Contains stream and media format info.
FieldTypeDescription
eventstring"start"
streamIdstringStream identifier
mediaFormatobjectAudio format metadata
Third event. Signals handshake complete, pipeline can start.
FieldTypeDescription
eventstring"answer"

Protocol events

Incoming (dialler → VoxCore)

EventDescription
mediaAudio frame. payload field contains base64-encoded LINEAR16 PCM.
hangup-callCustomer or network disconnection. disconnectedBy field indicates source.

Outgoing (VoxCore → dialler)

EventDescription
reverse-mediaBot audio response. Base64-encoded LINEAR16 PCM in payload.
reverse-media-stopClears the dialler’s audio buffer. Sent before hangup.
reverse-hangup-callDrops the call. Sent after reverse-media-stop.
reverse-call-transferTransfers the call to a specified number.

reverse-media payload

{
  "event": "reverse-media",
  "chunk": 42,
  "did": "+911234567890",
  "payload": "<base64 audio>",
  "timestamp": "2026-04-24 14:30:00",
  "streamId": "stream-abc",
  "callerId": "+919876543210",
  "chunk_durn_ms": 20,
  "callDirection": "incoming",
  "encoding": "LINEAR",
  "source": "ai"
}

Hangup behavior

Bot-initiated hangup:
  1. VoxCore sends reverse-media-stop (clears audio buffer)
  2. VoxCore sends reverse-hangup-call
  3. disconnected_by = "bot"
Customer hangup:
  1. Dialler sends hangup-call event
  2. VoxCore receives CancelFrame, pipeline winds down
  3. disconnected_by = "customer"

Capacity

When a worker is at MAX_CONCURRENT_CALLS, new WebSocket connections are rejected with close code 1008 (“Server at capacity”). The nginx least_conn balancer routes to the least-loaded worker.