Skip to main content

DialStack WebRTC Signalling Protocol 1.0.0 documentation

Real-time signalling protocol for DialStack WebRTC softphones.

Overview

The WebRTC signalling protocol enables softphone applications (web, mobile, desktop) to make and receive phone calls through DialStack. It handles call setup, media negotiation, call control, and presence — all over a single WebSocket connection.

Connection Flow

  1. Obtain a user token via POST /v1/user_sessions (see Authentication)
  2. Open a WebSocket connection to wss://api.dialstack.ai/v1/webrtc
  3. Send an authenticate message with the user token
  4. Receive an authenticated message confirming the session
  5. The connection is now ready for calls and presence

Authentication

The WebSocket connection itself does not use HTTP headers for authentication. Instead, the first message sent after connecting must be an authenticate message containing the user token. The server responds with authenticated on success or error on failure, closing the connection.

Subprotocol negotiation

The client MUST request the dialstack.webrtc.v1 subprotocol on the HTTP upgrade via Sec-WebSocket-Protocol. A server that doesn't speak the offered version rejects the upgrade. Browser SDK:

new WebSocket('wss://api.dialstack.ai/v1/webrtc', ['dialstack.webrtc.v1']);

When v2 ships, clients that want to remain backward-compatible can offer both: ['dialstack.webrtc.v2', 'dialstack.webrtc.v1'] and the server picks the highest one it supports.

Keepalive

Liveness is handled at the WebSocket protocol layer. The server sends a native WebSocket ping control frame every 30 seconds; the client's WS library responds with the matching pong transparently — no application message is required. If the server doesn't get a pong within ~10 seconds, it closes the connection with idle_timeout.

Reconnection

If the WebSocket connection drops:

  1. Wait with exponential backoff (1s, 2s, 4s, 8s, max 30s)
  2. Reconnect and re-authenticate
  3. Active calls survive brief disconnections (up to 30 seconds). The server holds call state and media continues flowing. On reconnection, the server sends call.restored for each active call so the client can rebuild its UI.

Message Format

All messages are JSON objects with a type field identifying the message kind. Messages from the client include a type and message-specific fields. Messages from the server include a type and message-specific fields.

Call Lifecycle

Outbound Call

Client Server
│ call.create (with sdp) ───> │
│ <────────────── call.trying │
│ <─────────────── sdp.answer │
│ ice.candidate ←──────────→ │ (bidirectional, multiple)
│ ice.done ────────────────> │
│ <──────────────── ice.done │
│ <────────────── call.ringing │
│ <──────────── call.answered │
│ ... call in progress ...
│ call.hangup ─────────────> │
│ <────────────── call.ended │

The browser generates the SDP offer (via RTCPeerConnection.createOffer()) and sends it inside call.create. The server responds with sdp.answer once Asterisk has answered the SIP INVITE. This matches the convention of every other WebRTC voice SDK (Twilio Voice JS, Vonage, LiveKit publish, JsSIP) and lets the browser start gathering ICE candidates in parallel with INVITE handling, shaving an RTT off call setup.

Inbound Call

Client Server
│ <──────────── call.incoming │
│ <─────────────── sdp.offer │
│ call.answer ─────────────> │
│ sdp.answer ──────────────> │
│ ice.candidate ←──────────→ │ (bidirectional, multiple)
│ <──────────── call.answered │
│ ... call in progress ...
│ <────────────── call.ended │

Table of Contents

Servers

dialstack Server

  • URL: wss://api.dialstack.ai/v1/webrtc
  • Protocol: wss

DialStack WebRTC signalling endpoint. Connect with a standard WebSocket client:

const ws = new WebSocket('wss://api.dialstack.ai/v1/webrtc');

Operations

SEND Authenticate Operation

Authenticate connection

  • Operation ID: sendAuthenticate

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Must be the first message sent after the WebSocket connection is established. The server responds with authenticated on success or error on failure. If authentication fails, the server closes the connection.

Message Authenticate authenticate

First message after connection — authenticates the user

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectAuthenticates the WebSocket connection with a user token.--additional properties are allowed
typestring-const ("authenticate")-required
req_idstringOptional client-chosen request correlation token, recommended on every client→server frame. The server echoes it on exactly one frame — the direct reply to the request: authenticated for this frame, call.trying for call-creating frames (call.create and the consult step of call.transfer.attended), or error on failure. State events caused by a request (call.held, call.ended, …) never carry a req_id — they can also occur for reasons other than your request.---
tokenstringUser token obtained from POST /v1/user_sessionsexamples ("eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...")-required
emergency_address_idstringOptional. The emergency-address resource id (from POST /v1/me/emergency-addresses) this softphone uses for E911. When present and the connection's network matches the address, the server uses it to route emergency calls with a dispatchable location. If the network no longer matches, the server replies (in addition to authenticated) with a network.changed message and the address is not used until re-confirmed. Emergency calls (911/933) are never blocked, with or without an address.examples ("emerg_01h2xcejqtf2nbrexx3vqjhp42")--

Examples of payload (generated)

{
"type": "authenticate",
"req_id": "string",
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"emergency_address_id": "emerg_01h2xcejqtf2nbrexx3vqjhp42"
}

RECEIVE Authenticated Operation

Authentication confirmed

  • Operation ID: receiveAuthenticated

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Confirms successful authentication. Contains session metadata and any active calls that were preserved during a reconnection.

Message Authenticated authenticated

Server confirms authentication and returns session info

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectConfirms successful authentication. Includes session and connection metadata.--additional properties are allowed
typestring-const ("authenticated")-required
req_idstringEchoes the req_id from the originating authenticate frame, when present.---
user_idstringAuthenticated user identifierexamples ("user_01h2xcejqtf2nbrexx3vqjhp42")-required
account_idstringAccount identifierexamples ("acct_01h2xcejqtf2nbrexx3vqjhp41")-required

Examples of payload (generated)

{
"type": "authenticated",
"req_id": "string",
"user_id": "user_01h2xcejqtf2nbrexx3vqjhp42",
"account_id": "acct_01h2xcejqtf2nbrexx3vqjhp41"
}

RECEIVE Error Operation

Error notification

  • Operation ID: receiveError

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Sent when an error occurs. The code field identifies the error type. Some errors are fatal (the server closes the connection after sending); others are informational (the connection remains open).

Message Error error

Protocol or call error

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectError notification. Fatal errors close the connection after sending.--additional properties are allowed
typestring-const ("error")-required
req_idstringEchoes the req_id of the originating client frame when the error is in response to one. Absent on server-initiated errors (e.g. going_away, session_limit, idle_timeout).---
codestringMachine-readable error codeallowed ("auth_failed", "auth_expired", "invalid_message", "call_failed", "call_not_found", "emergency_address_required", "session_limit", "rate_limited", "internal_error", "going_away", "idle_timeout", "slow_consumer")-required
messagestringHuman-readable error descriptionexamples ("Invalid or expired user token")-required
fatalbooleanIf true, the server will close the connection after this message---

Examples of payload (generated)

{
"type": "error",
"req_id": "string",
"code": "auth_failed",
"message": "Invalid or expired user token",
"fatal": false
}

RECEIVE Network Changed Operation

Emergency-address network advisory

  • Operation ID: receiveNetworkChanged

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Sent after authenticated when the emergency address presented on the handshake does not apply on the current network (E911). The session is unaffected for emergency calls; the app should prompt the user to confirm or register an address valid for this network before non-emergency calls.

Message Network Changed network.changed

*Advisory that the bound emergency address no longer applies on the current network (E911). The session stays usable and emergency calls still go out; non-emergency PSTN is gated until an address valid here is confirmed. *

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectAdvisory that the bound emergency address no longer applies on the current network (E911). Carries no fields beyond the discriminator.--additional properties are allowed
typestring-const ("network.changed")-required

Examples of payload (generated)

{
"type": "network.changed"
}

SEND Call Create Operation

Initiate outbound call

  • Operation ID: sendCallCreate

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Dials the specified destination. The client's SDP offer (from RTCPeerConnection.createOffer()) is carried in the sdp field. The server responds with call.trying, then sdp.answer once Asterisk accepts the SIP INVITE. ICE candidates are trickled in both directions to establish the media path.

Message Create Call call.create

Initiate an outbound call

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectInitiates an outbound call. The destination can be a phone number (E.164 format) or an extension dial code. The client generates a WebRTC SDP offer (RTCPeerConnection.createOffer()) and passes it in sdp. The server replies with sdp.answer once Asterisk accepts the SIP INVITE. ICE candidates are trickled bidirectionally as they're gathered.--additional properties are allowed
typestring-const ("call.create")-required
req_idstringOptional request correlation token. Echoed on this frame's direct reply — call.trying on success or error on failure — so the client can bind its provisional call object to the server-assigned call_id.examples ("req_a1b2c3d4")--
destinationstringPhone number in E.164 format (e.g., +14155551234) or an extension dial code (e.g., 105).examples ("+14155551234", "105")-required
sdpstringWebRTC SDP offer string from RTCPeerConnection.createOffer(). Becomes the body of the SIP INVITE the server sends to Asterisk; the answer comes back as sdp.answer.--required
caller_idstring | nullCaller ID number to display (E.164 format). Must be a phone number assigned to the account. If omitted, the account's default outbound caller ID is used.examples ("+14155559876")--

Examples of payload (generated)

{
"type": "call.create",
"req_id": "req_a1b2c3d4",
"destination": "+14155551234",
"sdp": "string",
"caller_id": "+14155559876"
}

RECEIVE Call Trying Operation

Outbound call is being processed

  • Operation ID: receiveCallTrying

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Confirms the server is processing the call request. The call_id in this message should be used for all subsequent messages about this call.

Message Call Trying call.trying

Server is processing the outbound call request

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectServer is processing the outbound call. Contains the server-assigned call_id to use for all subsequent messages about this call.--additional properties are allowed
typestring-const ("call.trying")-required
call_idstringServer-assigned call identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
req_idstring | nullEchoes the req_id of the frame that created this call (call.create or the consult step of call.transfer.attended). call.trying is that frame's direct reply.---

Examples of payload (generated)

{
"type": "call.trying",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"req_id": "string"
}

RECEIVE Call Ringing Operation

Remote party is ringing

  • Operation ID: receiveCallRinging

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

The destination phone is ringing. Play a ringback tone to the user.

Message Call Ringing call.ringing

Remote party's phone is ringing

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectThe remote party's phone is ringing.--additional properties are allowed
typestring-const ("call.ringing")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.ringing",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

RECEIVE Call Incoming Operation

Incoming call notification

  • Operation ID: receiveCallIncoming

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

An inbound call is arriving for this user. The message includes caller ID information and an sdp.offer follows immediately. The client should alert the user and, when they answer, respond with call.answer and sdp.answer.

The ring duration is controlled by the upstream caller (their PBX, the Find Me / Follow Me chain, or the dial plan node that routed to this user). When the upstream gives up, the server sends call.ended with reason no-answer. There is no server-side cap on ring time — clients should not assume a specific timeout.

Message Incoming Call call.incoming

An inbound call is arriving for this user

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectAn inbound call is arriving. An sdp.offer message follows immediately with the remote session description.--additional properties are allowed
typestring-const ("call.incoming")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
fromstringCaller's phone number (E.164 format)examples ("+14155551234")-required
from_namestring | nullCaller's display name (from caller ID, if available)examples ("John Smith")--
tostringCalled number or extensionexamples ("+14155559876")-required

Examples of payload (generated)

{
"type": "call.incoming",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"from": "+14155551234",
"from_name": "John Smith",
"to": "+14155559876"
}

SEND Call Answer Operation

Answer incoming call

  • Operation ID: sendCallAnswer

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Accepts an incoming call. Must be followed by sdp.answer with the local session description.

Message Answer Call call.answer

Answer an incoming call

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectAccepts an incoming call.--additional properties are allowed
typestring-const ("call.answer")-required
call_idstringCall identifier from the call.incoming messageexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.answer",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

SEND Call Reject Operation

Reject incoming call

  • Operation ID: sendCallReject

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Rejects an incoming call on this device. The call may continue ringing on the user's other devices.

Message Reject Call call.reject

Reject an incoming call

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectRejects an incoming call on this device. The call may continue ringing on the user's other devices.--additional properties are allowed
typestring-const ("call.reject")-required
call_idstringCall identifier from the call.incoming messageexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
reasonstringRejection reason: - busy — signal busy to the caller - decline — silently decline (no busy signal)default ("decline"), allowed ("busy", "decline")--

Examples of payload (generated)

{
"type": "call.reject",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"reason": "busy"
}

RECEIVE Call Answered Operation

Call connected

  • Operation ID: receiveCallAnswered

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

The call has been answered and media is flowing. For outbound calls, this means the remote party picked up. For inbound calls, this confirms the answer was processed.

Message Call Answered call.answered

Call has been answered (media is flowing)

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectThe call has been answered and media is flowing. For outbound calls, this means the remote party picked up. For inbound calls, this confirms the client's call.answer was processed.--additional properties are allowed
typestring-const ("call.answered")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
answered_atstringWhen the call was answered (ISO 8601)-format (date-time)-

Examples of payload (generated)

{
"type": "call.answered",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"answered_at": "2019-08-24T14:15:22Z"
}

SEND Call Hangup Operation

End a call

  • Operation ID: sendCallHangup

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Ends an active or ringing call. The server confirms with call.ended.

Message Hang Up call.hangup

End an active or ringing call

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectEnds an active or ringing call.--additional properties are allowed
typestring-const ("call.hangup")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.hangup",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

RECEIVE Call Ended Operation

Call ended

  • Operation ID: receiveCallEnded

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

The call has ended. The reason field indicates why (hangup, no-answer, busy, failed, transferred). After receiving this message, clean up any media resources for this call.

Message Call Ended call.ended

Call has ended

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectThe call has ended. Clean up media resources (close RTCPeerConnection).--additional properties are allowed
typestring-const ("call.ended")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
reasonstringWhy the call ended: - hangup — either party hung up - no-answer — timed out without answer - busy — destination returned busy - failed — call setup failed (network error, invalid destination) - transferred — call was transferred to another destination - rejected — the remote party rejected the callallowed ("hangup", "no-answer", "busy", "failed", "transferred", "rejected")-required
duration_secondsinteger | nullCall duration in seconds (null if never answered)---

Examples of payload (generated)

{
"type": "call.ended",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"reason": "hangup",
"duration_seconds": 0
}

RECEIVE Call Restored Operation

Active call restored after reconnection

  • Operation ID: receiveCallRestored

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Sent after authenticated when reconnecting with active calls. The client should rebuild its UI for each restored call. An sdp.offer follows for re-establishing the media path.

Message Call Restored call.restored

Active call restored after reconnection

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectSent after authenticated when reconnecting with an active call that was preserved during the disconnection (up to 30 seconds). An sdp.offer follows for re-establishing the media path. The client should close any existing RTCPeerConnection for this call and create a new one. Then handle the sdp.offer normally (set remote description, create answer, exchange ICE candidates).--additional properties are allowed
typestring-const ("call.restored")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
statestringCurrent state of the restored callallowed ("ringing", "active", "held")-required
fromstringCaller's phone number--required
from_namestring | nullCaller's display name---
tostringCalled number or extension--required
directionstring-allowed ("inbound", "outbound")--
answered_atstring | nullWhen the call was answered (null if still ringing)-format (date-time)-

Examples of payload (generated)

{
"type": "call.restored",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"state": "ringing",
"from": "string",
"from_name": "string",
"to": "string",
"direction": "inbound",
"answered_at": "2019-08-24T14:15:22Z"
}

SEND Sdp Offer Operation

Send SDP offer

  • Operation ID: sendSdpOffer

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Send a local session description offer. Used during call setup and mid-call renegotiation (e.g., codec change, hold with sendonly).

Message SDP Offer sdp.offer

SDP offer for media negotiation

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectSDP offer for media negotiation. Sent by the server for inbound calls and outbound call setup. Sent by the client during renegotiation.--additional properties are allowed
typestring-const ("sdp.offer")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
sdpstringSDP (Session Description Protocol) offer string. Pass this to RTCPeerConnection.setRemoteDescription() as an offer.--required

Examples of payload (generated)

{
"type": "sdp.offer",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"sdp": "string"
}

RECEIVE Sdp Offer Operation

Receive SDP offer

  • Operation ID: receiveSdpOffer

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Server sends an SDP offer for the client to answer. This happens for inbound calls (the browser is the called party), for the consultation leg of an attended transfer (the consult target is effectively a new inbound call to the transferring user), for call.restored (re-establishing media after a WS reconnect), and for any mid-call renegotiation initiated by the server. Outbound call setup uses the reverse direction: the client sends its offer inside call.create and receives sdp.answer.

Message SDP Offer sdp.offer

SDP offer for media negotiation

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectSDP offer for media negotiation. Sent by the server for inbound calls and outbound call setup. Sent by the client during renegotiation.--additional properties are allowed
typestring-const ("sdp.offer")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
sdpstringSDP (Session Description Protocol) offer string. Pass this to RTCPeerConnection.setRemoteDescription() as an offer.--required

Examples of payload (generated)

{
"type": "sdp.offer",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"sdp": "string"
}

SEND Sdp Answer Operation

Send SDP answer

  • Operation ID: sendSdpAnswer

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Respond to an SDP offer with a local session description answer.

Message SDP Answer sdp.answer

SDP answer for media negotiation

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectSDP answer for media negotiation. Sent by the client in response to an sdp.offer. The SDP should be obtained from RTCPeerConnection.createAnswer().--additional properties are allowed
typestring-const ("sdp.answer")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
sdpstringSDP answer string from RTCPeerConnection.createAnswer(). Pass the received offer to setRemoteDescription() first, then create and send the answer.--required

Examples of payload (generated)

{
"type": "sdp.answer",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"sdp": "string"
}

RECEIVE Sdp Answer Operation

Receive SDP answer

  • Operation ID: receiveSdpAnswer

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Server responds to the client's SDP offer with an answer.

Message SDP Answer sdp.answer

SDP answer for media negotiation

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectSDP answer for media negotiation. Sent by the client in response to an sdp.offer. The SDP should be obtained from RTCPeerConnection.createAnswer().--additional properties are allowed
typestring-const ("sdp.answer")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
sdpstringSDP answer string from RTCPeerConnection.createAnswer(). Pass the received offer to setRemoteDescription() first, then create and send the answer.--required

Examples of payload (generated)

{
"type": "sdp.answer",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"sdp": "string"
}

SEND Ice Candidate Operation

Send ICE candidate

  • Operation ID: sendIceCandidate

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Send a locally gathered ICE candidate. Candidates are trickled as they are discovered — send each one immediately for the fastest call setup.

Message ICE Candidate ice.candidate

ICE candidate for connectivity checks

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectICE candidate for connectivity checks. Trickled bidirectionally as candidates are gathered. Each candidate should be added to the peer connection immediately with RTCPeerConnection.addIceCandidate().--additional properties are allowed
typestring-const ("ice.candidate")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
candidatestringICE candidate string from the RTCIceCandidate.candidate property.examples ("candidate:842163049 1 udp 1677729535 203.0.113.1 44323 typ srflx raddr 192.168.1.100 rport 44323")-required
sdp_midstring | nullMedia stream identification tagexamples ("0")--
sdp_m_line_indexinteger | nullIndex of the media description in the SDP---

Examples of payload (generated)

{
"type": "ice.candidate",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"candidate": "candidate:842163049 1 udp 1677729535 203.0.113.1 44323 typ srflx raddr 192.168.1.100 rport 44323",
"sdp_mid": "0",
"sdp_m_line_index": 0
}

RECEIVE Ice Candidate Operation

Receive ICE candidate

  • Operation ID: receiveIceCandidate

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Server sends a remote ICE candidate. Add it to the peer connection with RTCPeerConnection.addIceCandidate().

Message ICE Candidate ice.candidate

ICE candidate for connectivity checks

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectICE candidate for connectivity checks. Trickled bidirectionally as candidates are gathered. Each candidate should be added to the peer connection immediately with RTCPeerConnection.addIceCandidate().--additional properties are allowed
typestring-const ("ice.candidate")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
candidatestringICE candidate string from the RTCIceCandidate.candidate property.examples ("candidate:842163049 1 udp 1677729535 203.0.113.1 44323 typ srflx raddr 192.168.1.100 rport 44323")-required
sdp_midstring | nullMedia stream identification tagexamples ("0")--
sdp_m_line_indexinteger | nullIndex of the media description in the SDP---

Examples of payload (generated)

{
"type": "ice.candidate",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"candidate": "candidate:842163049 1 udp 1677729535 203.0.113.1 44323 typ srflx raddr 192.168.1.100 rport 44323",
"sdp_mid": "0",
"sdp_m_line_index": 0
}

SEND Ice Done Operation

ICE gathering complete

  • Operation ID: sendIceDone

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

All local ICE candidates have been gathered. This signals the end of trickle ICE from the client side.

Message ICE Done ice.done

All ICE candidates have been gathered

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectAll ICE candidates have been gathered. No more ice.candidate messages will be sent for this call from this side.--additional properties are allowed
typestring-const ("ice.done")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "ice.done",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

RECEIVE Ice Done Operation

Remote ICE gathering complete

  • Operation ID: receiveIceDone

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

All remote ICE candidates have been sent. No more candidates will arrive for this call.

Message ICE Done ice.done

All ICE candidates have been gathered

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectAll ICE candidates have been gathered. No more ice.candidate messages will be sent for this call from this side.--additional properties are allowed
typestring-const ("ice.done")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "ice.done",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

SEND Call Hold Operation

Hold call

  • Operation ID: sendCallHold

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Places the call on hold. The server confirms with call.held and plays hold music to the remote party.

Message Hold Call call.hold

Place an active call on hold

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectPlaces the specified call on hold.--additional properties are allowed
typestring-const ("call.hold")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.hold",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

SEND Call Resume Operation

Resume call

  • Operation ID: sendCallResume

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Resumes a held call. The server confirms with call.resumed.

Message Resume Call call.resume

Resume a held call

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectResumes a held call.--additional properties are allowed
typestring-const ("call.resume")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.resume",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

RECEIVE Call Held Operation

Call placed on hold

  • Operation ID: receiveCallHeld

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Confirms the call was placed on hold. The held_by field indicates whether the local user or the remote party initiated the hold.

Message Call Held call.held

Call was placed on hold (by local or remote party)

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectConfirms the call was placed on hold.--additional properties are allowed
typestring-const ("call.held")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
held_bystringWho initiated the hold: - local — this user placed the call on hold - remote — the remote party placed the call on holdallowed ("local", "remote")-required

Examples of payload (generated)

{
"type": "call.held",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"held_by": "local"
}

RECEIVE Call Resumed Operation

Call resumed

  • Operation ID: receiveCallResumed

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Confirms a held call was resumed. Media resumes flowing.

Message Call Resumed call.resumed

Held call was resumed

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectConfirms a held call was resumed.--additional properties are allowed
typestring-const ("call.resumed")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.resumed",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

SEND Call Mute Operation

Server-side mute

  • Operation ID: sendCallMute

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Mutes the user's audio at the server. The remote party hears silence. This is in addition to any client-side mute (disabling the microphone track). Server-side mute is authoritative — even if the client sends audio, it is not forwarded.

Message Mute call.mute

Mute the microphone (server-side)

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectMutes the user's audio at the server. The remote party hears silence regardless of whether the client is sending audio.--additional properties are allowed
typestring-const ("call.mute")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.mute",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

SEND Call Unmute Operation

Server-side unmute

  • Operation ID: sendCallUnmute

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Unmutes the user's audio at the server.

Message Unmute call.unmute

Unmute the microphone (server-side)

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectUnmutes the user's audio at the server.--additional properties are allowed
typestring-const ("call.unmute")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required

Examples of payload (generated)

{
"type": "call.unmute",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45"
}

SEND Call Transfer Operation

Blind transfer

  • Operation ID: sendCallTransfer

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Transfers the call to another destination without consulting the transfer target first. The call is immediately redirected and this client's participation ends. The server sends call.ended with reason transferred.

Message Blind Transfer call.transfer

Transfer the call to another destination

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectBlind transfer — immediately redirects the call to another destination. The current client's participation ends after the transfer.--additional properties are allowed
typestring-const ("call.transfer")-required
call_idstringCall identifierexamples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
destinationstringTransfer destination (E.164 number or extension)examples ("105", "+14155551234")-required

Examples of payload (generated)

{
"type": "call.transfer",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"destination": "105"
}

SEND Call Transfer Attended Operation

Attended transfer

  • Operation ID: sendCallTransferAttended

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Performs an attended (consultative) transfer in two steps:

Step 1 — Consult (step: "consult"): Send with a destination and an sdp offer (the consultation leg reuses the outbound call flow, so the client supplies its offer here exactly as it does in call.create). The server:

  1. Places the original call on hold (sends call.held with held_by: "local")
  2. Initiates a new call to the transfer target using the supplied offer
  3. Sends call.trying with a new call_id for the consultation call
  4. Sends sdp.answer for the consultation call's media
  5. Normal call setup follows (call.ringing, call.answered)

The client now has two calls: the original (held) and the consultation (active).

Step 2 — Complete (step: "complete"): Send to bridge the original caller with the transfer target. The server:

  1. Sends call.ended with reason transferred for the original call
  2. Sends call.ended with reason transferred for the consultation call
  3. The original caller and transfer target are connected directly

Cancelling: Send call.hangup for the consultation call. The server ends the consultation call and resumes the original call automatically.

Failure: If the consultation call fails (busy, no-answer), the server ends the consultation call and resumes the original call automatically.

Message Attended Transfer call.transfer.attended

Start or complete an attended (consultative) transfer

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectAttended (consultative) transfer. Send with step "consult" to dial the target, then "complete" to bridge the calls.--additional properties are allowed
typestring-const ("call.transfer.attended")-required
call_idstringFor consult: the call identifier of the original call to be transferred. For complete: the call identifier of the original call.examples ("call_01h2xcejqtf2nbrexx3vqjhp45")-required
stepstringTransfer step: - consult — hold the current call and dial the transfer target - complete — connect the original caller to the transfer targetallowed ("consult", "complete")-required
destinationstringTransfer destination (required for consult step, ignored for complete). E.164 number or extension.examples ("105")--
sdpstringSDP offer for the consultation leg (required for consult step, ignored for complete). The consultation reuses the outbound call flow, so the client supplies its offer here as it does in call.create; the server replies with sdp.answer.---
req_idstringOptional request correlation token. The consult step is a call-creating frame, so its direct reply is the consultation's call.trying, which echoes this value — exactly like call.create. On failure, the error frame echoes it instead.examples ("req_lx3k9f_2")--

Examples of payload (generated)

{
"type": "call.transfer.attended",
"call_id": "call_01h2xcejqtf2nbrexx3vqjhp45",
"step": "consult",
"destination": "105",
"sdp": "string",
"req_id": "req_lx3k9f_2"
}

SEND Presence Subscribe Operation

Subscribe to presence updates

  • Operation ID: sendPresenceSubscribe

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Subscribes to real-time presence updates for users in the account. The server responds with presence.list containing the current status of all users, then sends presence.update messages as statuses change.

Message Subscribe to Presence presence.subscribe

Subscribe to presence updates for users in the account

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectSubscribe to presence updates. The server responds with presence.list containing all users' current status, then sends presence.update messages as statuses change.--additional properties are allowed
typestring-const ("presence.subscribe")-required
user_idsarray<string>Specific user IDs to subscribe to. If omitted, subscribes to all users in the account.---
user_ids (single item)string----

Examples of payload (generated)

{
"type": "presence.subscribe",
"user_ids": [
"string"
]
}

RECEIVE Presence List Operation

Presence snapshot

  • Operation ID: receivePresenceList

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

Sent in response to presence.subscribe. Contains the current presence status of all users in the account. Use this to populate the initial state of a buddy list or BLF panel.

Message Presence Snapshot presence.list

Initial presence snapshot after subscribing

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectPresence snapshot of all subscribed users. Sent in response to presence.subscribe.--additional properties are allowed
typestring-const ("presence.list")-required
usersarray<object>Current presence status for each subscribed user--required
users.user_idstringUser identifierexamples ("user_01h2xcejqtf2nbrexx3vqjhp42")-required
users.namestringUser's display nameexamples ("Jane Doe")-required
users.statusstringCurrent presence statusallowed ("available", "on_call", "dnd", "away", "offline")-required
users.status_textstring | nullOptional custom status message---
users.updated_atstring--format (date-time)-

Examples of payload (generated)

{
"type": "presence.list",
"users": [
{
"user_id": "user_01h2xcejqtf2nbrexx3vqjhp42",
"name": "Jane Doe",
"status": "available",
"status_text": "string",
"updated_at": "2019-08-24T14:15:22Z"
}
]
}

RECEIVE Presence Update Operation

Presence changed

  • Operation ID: receivePresenceUpdate

Bidirectional signalling channel for WebRTC call setup, control, and presence. A single WebSocket connection handles all calls for the authenticated user, including multiple simultaneous calls.

A user's presence status has changed (e.g., went on a call, set DND, came online). Update the UI for the affected user.

Message Presence Update presence.update

A user's presence status has changed

Payload
NameTypeDescriptionValueConstraintsNotes
(root)objectA user's presence status has changed.--additional properties are allowed
typestring-const ("presence.update")-required
user_idstringUser whose presence changedexamples ("user_01h2xcejqtf2nbrexx3vqjhp42")-required
statusstringNew presence statusallowed ("available", "on_call", "dnd", "away", "offline")-required
status_textstring | nullOptional custom status message---
updated_atstring--format (date-time)-

Examples of payload (generated)

{
"type": "presence.update",
"user_id": "user_01h2xcejqtf2nbrexx3vqjhp42",
"status": "available",
"status_text": "string",
"updated_at": "2019-08-24T14:15:22Z"
}