DialStack WebRTC Signalling Protocol 1.0.0 documentation
- Support: DialStack API Support
- Email support: info@dialstack.ai
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
- Obtain a user token via
POST /v1/user_sessions(see Authentication) - Open a WebSocket connection to
wss://api.dialstack.ai/v1/webrtc - Send an
authenticatemessage with the user token - Receive an
authenticatedmessage confirming the session - 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:
- Wait with exponential backoff (1s, 2s, 4s, 8s, max 30s)
- Reconnect and re-authenticate
- Active calls survive brief disconnections (up to 30 seconds). The server
holds call state and media continues flowing. On reconnection, the server
sends
call.restoredfor 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 │
Related Documentation
- REST API Reference — User sessions, ICE servers, User Profile endpoints
- WebRTC Guide — Integration guide with code examples
- Mobile & Push Notifications — Mobile incoming call notifications
- Download AsyncAPI Spec — Raw YAML specification
Table of Contents
- Servers
- Operations
- SEND Authenticate
- RECEIVE Authenticated
- RECEIVE Error
- RECEIVE Network Changed
- SEND Call Create
- RECEIVE Call Trying
- RECEIVE Call Ringing
- RECEIVE Call Incoming
- SEND Call Answer
- SEND Call Reject
- RECEIVE Call Answered
- SEND Call Hangup
- RECEIVE Call Ended
- RECEIVE Call Restored
- SEND Sdp Offer
- RECEIVE Sdp Offer
- SEND Sdp Answer
- RECEIVE Sdp Answer
- SEND Ice Candidate
- RECEIVE Ice Candidate
- SEND Ice Done
- RECEIVE Ice Done
- SEND Call Hold
- SEND Call Resume
- RECEIVE Call Held
- RECEIVE Call Resumed
- SEND Call Mute
- SEND Call Unmute
- SEND Call Transfer
- SEND Call Transfer Attended
- SEND Presence Subscribe
- RECEIVE Presence List
- RECEIVE Presence Update
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
- Message ID:
authenticate - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Authenticates the WebSocket connection with a user token. | - | - | additional properties are allowed |
| type | string | - | const ("authenticate") | - | required |
| req_id | string | Optional 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. | - | - | - |
| token | string | User token obtained from POST /v1/user_sessions | examples ("eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...") | - | required |
| emergency_address_id | string | Optional. 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
- Message ID:
authenticated - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Confirms successful authentication. Includes session and connection metadata. | - | - | additional properties are allowed |
| type | string | - | const ("authenticated") | - | required |
| req_id | string | Echoes the req_id from the originating authenticate frame, when present. | - | - | - |
| user_id | string | Authenticated user identifier | examples ("user_01h2xcejqtf2nbrexx3vqjhp42") | - | required |
| account_id | string | Account identifier | examples ("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
- Message ID:
error - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Error notification. Fatal errors close the connection after sending. | - | - | additional properties are allowed |
| type | string | - | const ("error") | - | required |
| req_id | string | Echoes 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). | - | - | - |
| code | string | Machine-readable error code | allowed ("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 |
| message | string | Human-readable error description | examples ("Invalid or expired user token") | - | required |
| fatal | boolean | If 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. *
- Message ID:
networkChanged - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Advisory that the bound emergency address no longer applies on the current network (E911). Carries no fields beyond the discriminator. | - | - | additional properties are allowed |
| type | string | - | 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
- Message ID:
callCreate - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Initiates 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 |
| type | string | - | const ("call.create") | - | required |
| req_id | string | Optional 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") | - | - |
| destination | string | Phone number in E.164 format (e.g., +14155551234) or an extension dial code (e.g., 105). | examples ("+14155551234", "105") | - | required |
| sdp | string | WebRTC 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_id | string | null | Caller 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
- Message ID:
callTrying - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Server is processing the outbound call. Contains the server-assigned call_id to use for all subsequent messages about this call. | - | - | additional properties are allowed |
| type | string | - | const ("call.trying") | - | required |
| call_id | string | Server-assigned call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| req_id | string | null | Echoes 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
- Message ID:
callRinging - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | The remote party's phone is ringing. | - | - | additional properties are allowed |
| type | string | - | const ("call.ringing") | - | required |
| call_id | string | Call identifier | examples ("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
- Message ID:
callIncoming - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | An inbound call is arriving. An sdp.offer message follows immediately with the remote session description. | - | - | additional properties are allowed |
| type | string | - | const ("call.incoming") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| from | string | Caller's phone number (E.164 format) | examples ("+14155551234") | - | required |
| from_name | string | null | Caller's display name (from caller ID, if available) | examples ("John Smith") | - | - |
| to | string | Called number or extension | examples ("+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
- Message ID:
callAnswer - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Accepts an incoming call. | - | - | additional properties are allowed |
| type | string | - | const ("call.answer") | - | required |
| call_id | string | Call identifier from the call.incoming message | examples ("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
- Message ID:
callReject - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Rejects an incoming call on this device. The call may continue ringing on the user's other devices. | - | - | additional properties are allowed |
| type | string | - | const ("call.reject") | - | required |
| call_id | string | Call identifier from the call.incoming message | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| reason | string | Rejection 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)
- Message ID:
callAnswered - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | 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 client's call.answer was processed. | - | - | additional properties are allowed |
| type | string | - | const ("call.answered") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| answered_at | string | When 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
- Message ID:
callHangup - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Ends an active or ringing call. | - | - | additional properties are allowed |
| type | string | - | const ("call.hangup") | - | required |
| call_id | string | Call identifier | examples ("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
- Message ID:
callEnded - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | The call has ended. Clean up media resources (close RTCPeerConnection). | - | - | additional properties are allowed |
| type | string | - | const ("call.ended") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| reason | string | Why 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 call | allowed ("hangup", "no-answer", "busy", "failed", "transferred", "rejected") | - | required |
| duration_seconds | integer | null | Call 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
- Message ID:
callRestored - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Sent 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 |
| type | string | - | const ("call.restored") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| state | string | Current state of the restored call | allowed ("ringing", "active", "held") | - | required |
| from | string | Caller's phone number | - | - | required |
| from_name | string | null | Caller's display name | - | - | - |
| to | string | Called number or extension | - | - | required |
| direction | string | - | allowed ("inbound", "outbound") | - | - |
| answered_at | string | null | When 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
- Message ID:
sdpOffer - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | SDP 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 |
| type | string | - | const ("sdp.offer") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| sdp | string | SDP (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
- Message ID:
sdpOffer - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | SDP 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 |
| type | string | - | const ("sdp.offer") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| sdp | string | SDP (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
- Message ID:
sdpAnswer - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | SDP 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 |
| type | string | - | const ("sdp.answer") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| sdp | string | SDP 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
- Message ID:
sdpAnswer - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | SDP 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 |
| type | string | - | const ("sdp.answer") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| sdp | string | SDP 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
- Message ID:
iceCandidate - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | ICE 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 |
| type | string | - | const ("ice.candidate") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| candidate | string | ICE 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_mid | string | null | Media stream identification tag | examples ("0") | - | - |
| sdp_m_line_index | integer | null | Index 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
- Message ID:
iceCandidate - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | ICE 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 |
| type | string | - | const ("ice.candidate") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| candidate | string | ICE 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_mid | string | null | Media stream identification tag | examples ("0") | - | - |
| sdp_m_line_index | integer | null | Index 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
- Message ID:
iceDone - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | All ICE candidates have been gathered. No more ice.candidate messages will be sent for this call from this side. | - | - | additional properties are allowed |
| type | string | - | const ("ice.done") | - | required |
| call_id | string | Call identifier | examples ("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
- Message ID:
iceDone - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | All ICE candidates have been gathered. No more ice.candidate messages will be sent for this call from this side. | - | - | additional properties are allowed |
| type | string | - | const ("ice.done") | - | required |
| call_id | string | Call identifier | examples ("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
- Message ID:
callHold - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Places the specified call on hold. | - | - | additional properties are allowed |
| type | string | - | const ("call.hold") | - | required |
| call_id | string | Call identifier | examples ("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
- Message ID:
callResume - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Resumes a held call. | - | - | additional properties are allowed |
| type | string | - | const ("call.resume") | - | required |
| call_id | string | Call identifier | examples ("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)
- Message ID:
callHeld - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Confirms the call was placed on hold. | - | - | additional properties are allowed |
| type | string | - | const ("call.held") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| held_by | string | Who initiated the hold: - local — this user placed the call on hold - remote — the remote party placed the call on hold | allowed ("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
- Message ID:
callResumed - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Confirms a held call was resumed. | - | - | additional properties are allowed |
| type | string | - | const ("call.resumed") | - | required |
| call_id | string | Call identifier | examples ("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)
- Message ID:
callMute - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Mutes the user's audio at the server. The remote party hears silence regardless of whether the client is sending audio. | - | - | additional properties are allowed |
| type | string | - | const ("call.mute") | - | required |
| call_id | string | Call identifier | examples ("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)
- Message ID:
callUnmute - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Unmutes the user's audio at the server. | - | - | additional properties are allowed |
| type | string | - | const ("call.unmute") | - | required |
| call_id | string | Call identifier | examples ("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
- Message ID:
callTransfer - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Blind transfer — immediately redirects the call to another destination. The current client's participation ends after the transfer. | - | - | additional properties are allowed |
| type | string | - | const ("call.transfer") | - | required |
| call_id | string | Call identifier | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| destination | string | Transfer 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:
- Places the original call on hold (sends
call.heldwithheld_by: "local") - Initiates a new call to the transfer target using the supplied offer
- Sends
call.tryingwith a newcall_idfor the consultation call - Sends
sdp.answerfor the consultation call's media - 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:
- Sends
call.endedwith reasontransferredfor the original call - Sends
call.endedwith reasontransferredfor the consultation call - 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
- Message ID:
callTransferAttended - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Attended (consultative) transfer. Send with step "consult" to dial the target, then "complete" to bridge the calls. | - | - | additional properties are allowed |
| type | string | - | const ("call.transfer.attended") | - | required |
| call_id | string | For consult: the call identifier of the original call to be transferred. For complete: the call identifier of the original call. | examples ("call_01h2xcejqtf2nbrexx3vqjhp45") | - | required |
| step | string | Transfer step: - consult — hold the current call and dial the transfer target - complete — connect the original caller to the transfer target | allowed ("consult", "complete") | - | required |
| destination | string | Transfer destination (required for consult step, ignored for complete). E.164 number or extension. | examples ("105") | - | - |
| sdp | string | SDP 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_id | string | Optional 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
- Message ID:
presenceSubscribe - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Subscribe 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 |
| type | string | - | const ("presence.subscribe") | - | required |
| user_ids | array<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
- Message ID:
presenceList - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | Presence snapshot of all subscribed users. Sent in response to presence.subscribe. | - | - | additional properties are allowed |
| type | string | - | const ("presence.list") | - | required |
| users | array<object> | Current presence status for each subscribed user | - | - | required |
| users.user_id | string | User identifier | examples ("user_01h2xcejqtf2nbrexx3vqjhp42") | - | required |
| users.name | string | User's display name | examples ("Jane Doe") | - | required |
| users.status | string | Current presence status | allowed ("available", "on_call", "dnd", "away", "offline") | - | required |
| users.status_text | string | null | Optional custom status message | - | - | - |
| users.updated_at | string | - | - | 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
- Message ID:
presenceUpdate - Content type: application/json
Payload
| Name | Type | Description | Value | Constraints | Notes |
|---|---|---|---|---|---|
| (root) | object | A user's presence status has changed. | - | - | additional properties are allowed |
| type | string | - | const ("presence.update") | - | required |
| user_id | string | User whose presence changed | examples ("user_01h2xcejqtf2nbrexx3vqjhp42") | - | required |
| status | string | New presence status | allowed ("available", "on_call", "dnd", "away", "offline") | - | required |
| status_text | string | null | Optional custom status message | - | - | - |
| updated_at | string | - | - | 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"
}