WebSocket events

Track the lifecycle and activity of WebSocket audio relays.
View as Markdown

WebSocket events are lifecycle webhooks and control-plane callbacks for an audio relay between a session and your wss:// backend — started with the websocket/start command, or born with a standalone type: "websocket" session that has no phone leg. They report relay connection, termination, failure, and backend text frames. A session can have at most one relay active at a time; a second websocket/start while one is already running returns 409.

All webhook deliveries are signed. See Verifying signatures for how to validate event authenticity.

websocket.connected

Fired when your backend accepts the relay’s WebSocket connection and audio begins flowing. For a standalone WebSocket session, this is also when the session advances from connecting to answered.

Payload schema

FieldTypeDescription
eventstringAlways "websocket.connected". Required
session_uuidstringThe session the relay is attached to. Required
timestampstringRFC 3339 / ISO 8601 UTC timestamp at which the event was emitted (e.g. "2025-06-06T08:53:20.000Z"). Required
1{
2 "event": "websocket.connected",
3 "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
4 "timestamp": "2025-06-06T08:53:20.000Z"
5}

websocket.disconnected

Fired when the relay reports a server-initiated close or error. A deliberate websocket/stop does not emit this event. On an unexpected close of a standalone WebSocket session, the session also ends, so a call.ended follows.

Payload schema

FieldTypeDescription
eventstringAlways "websocket.disconnected". Required
session_uuidstringThe session the relay was attached to. Required
codeintegerWebSocket close code (e.g. 1000 for a normal close), or 0 when unavailable. Required
reasonstringHuman-readable close reason (e.g. "bye"), or an empty string when unavailable. Required
timestampstringRFC 3339 / ISO 8601 UTC timestamp at which the event was emitted. Required
1{
2 "event": "websocket.disconnected",
3 "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
4 "code": 1000,
5 "reason": "bye",
6 "timestamp": "2025-06-06T08:55:01.000Z"
7}

websocket.failed

Fired when the relay cannot be established — your backend is unreachable, rejects the handshake, or the connection drops before it is usable. On a standalone WebSocket session the session ends, so a call.ended follows.

Payload schema

FieldTypeDescription
eventstringAlways "websocket.failed". Required
session_uuidstringThe session the relay was attached to. Required
http_statusintegerHTTP status returned by your backend during the handshake (e.g. 401), or 0 when unavailable. Required
errorstringFailure category. One of "handshake_failed" or "connection_failed". Required
timestampstringRFC 3339 / ISO 8601 UTC timestamp at which the event was emitted. Required
1{
2 "event": "websocket.failed",
3 "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
4 "http_status": 401,
5 "error": "handshake_failed",
6 "timestamp": "2025-06-06T08:53:21.000Z"
7}

websocket.message_received

Fired when your backend sends a text frame back over the relay. Use it for out-of-band control or metadata from your backend. To send a final text frame before closing the relay, use websocket/stop with final_text.

Payload schema

FieldTypeDescription
eventstringAlways "websocket.message_received". Required
session_uuidstringThe session the relay is attached to. Required
datastringThe text frame sent by your backend (size-capped). Required
timestampstringRFC 3339 / ISO 8601 UTC timestamp at which the event was emitted. Required
1{
2 "event": "websocket.message_received",
3 "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
4 "data": "{\"intent\":\"transfer\"}",
5 "timestamp": "2025-06-06T08:54:10.000Z"
6}

websocket.audio_playback_completed

Fired when the relay has played all the backend audio it had buffered and is now idle — useful to know your backend has finished speaking.

Payload schema

FieldTypeDescription
eventstringAlways "websocket.audio_playback_completed". Required
session_uuidstringThe session the relay is attached to. Required
played_msintegerMilliseconds of backend audio played before going idle (e.g. 4200), or 0 when unavailable. Required
timestampstringRFC 3339 / ISO 8601 UTC timestamp at which the event was emitted. Required
1{
2 "event": "websocket.audio_playback_completed",
3 "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
4 "played_ms": 4200,
5 "timestamp": "2025-06-06T08:54:25.000Z"
6}

Dispatch acknowledgement events

The relay control commands each emit a short acknowledgement event. It confirms that the command was accepted, not that the audio change has taken effect. These events carry event, session_uuid, operation_uuid, and timestamp.

1{
2 "event": "command.websocket.pause.accepted",
3 "session_uuid": "acW68-f47ac10b-58cc-4372-a567-0e02b2c3d479",
4 "operation_uuid": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
5 "timestamp": "2025-06-06T08:54:30.000Z"
6}

command.websocket.pause.accepted

Confirms dispatch of websocket/pause, which requests pausing audio in both directions while keeping the connection open. It stops sending user audio to the backend and stops playing backend audio to the session. Pausing does not flush buffered backend audio.

command.websocket.resume.accepted

Confirms dispatch of websocket/resume, which requests resuming audio in both directions. It does not unmute either leg; mute settings applied before or during the pause remain in effect.

command.websocket.mute.accepted

Confirms dispatch of websocket/mute, which requests muting a leg (user, backend, or all).

command.websocket.unmute.accepted

Confirms dispatch of websocket/unmute, which requests unmuting a leg.

command.websocket.flush.accepted

Confirms dispatch of websocket/flush, which requests discarding buffered backend audio (barge-in).

Triggered by

CommandWebhooksTiming
websocket/startwebsocket.connected or websocket.failed (then websocket.disconnected later when the relay closes)Asynchronous
websocket/stopcall.ended for a standalone WebSocket session; no webhook for a relay attached to a phone callImmediate
websocket/pausecommand.websocket.pause.acceptedImmediate
websocket/resumecommand.websocket.resume.acceptedImmediate
websocket/mutecommand.websocket.mute.acceptedImmediate
websocket/unmutecommand.websocket.unmute.acceptedImmediate
websocket/flushcommand.websocket.flush.acceptedImmediate

websocket.message_received and websocket.audio_playback_completed are backend-driven — they fire whenever your backend sends a text frame or finishes playing its buffered audio, not in response to a command.