This is the stream behind Live Monitoring in the dashboard. For a call that has already ended, use Get Call instead: it returns the final transcript with word timestamps and, when PII scrubbing is on, the scrubbed version.
Overview
The monitor call WebSocket streams a live call’s transcript to your server while the call is in progress. Connect with your API key to receive every agent and user turn, tool call, and node transition as JSON events, starting with a snapshot of the conversation so far and ending when the call ends. Your server opens this connection and Retell sends events on it. Your server doesn’t send anything back. Use it when you need the conversation while it’s still happening:- Show live transcripts in your own tools. Build a supervisor console, embed the transcript in your CRM, or mirror the call in an internal dashboard.
- React mid-call. Page a human when the flow reaches an escalation node, alert on a failed tool call, or flag a keyword before the call ends.
- Audit in real time. Watch sensitive conversations as they happen instead of only in review.
Endpoint
WebSocket endpoint:
wss://api.retellai.com/v2/monitor-call/{call_id}Path parameters
string
required
Id of the call to monitor. The call must belong to your workspace and be in progress (
call_status is ongoing).Headers
string
required
Bearer YOUR_RETELL_API_KEY, the same as for REST requests. A key with restricted permissions needs Call → Edit. Keys without restrictions work as is. See Manage API keys.Connection limits
- The call must be
ongoing. A registered call that hasn’t connected yet, or a call that has ended, is rejected with close code 4004. Connect when you receive thecall_startedwebhook, or once Get Call reportsongoing. - Up to 5 connections per call (as of September 2026). Dashboard viewers count toward the same limit. A sixth connection is rejected with close code 4008 and the reason
max watchers reached.
Protocol
Retell sends events to your server over this WebSocket following the protocol below. All messages are text frames whosedata is a stringified JSON object. Check the type field to tell events apart.
The stream carries text only. Transcript items have the text and a start time, not per-word timing, so fetch the call with Get Call after it ends for word timestamps. During an agentic warm transfer, the transfer agent’s conversation with the transfer target isn’t streamed; it appears in the Get Call transcript as transfer_target utterances after the call. The text is always the raw transcript: PII scrubbing runs after a call ends, so no scrubbed version exists mid-call. Treat the stream as sensitive data. To hear live audio, use Live Listen in the dashboard.
Event flow
Once Retell validates your key and the call, it admits the connection and sends one transcript snapshot event with everything said so far, so a connection that joins mid-call starts complete. As the call goes on, each change arrives as a transcript updated event: a new user or agent turn, more text on the current turn, a tool call and its result, a node transition, a keypad press, an SMS, or injected context. When the call ends, Retell sends a call ended event and closes the connection with code 1000 and the reasoncall_ended.
Every transcript item has a stable id. When an id arrives again, the new item replaces the old one: as a speaker keeps talking, their current turn is re-sent with the full text so far. Keep items in a map keyed by id and sort by time_sec for display, and you have the live transcript. The snapshot can arrive after the first updates, so apply the same replace-by-id logic to both.
If your connection drops while the call is still ongoing, reconnect. The new connection gets a fresh snapshot, and replace-by-id handles any overlap. If the call’s server disappears without sending call_ended (for example, an infrastructure failure), Retell closes the connection within about a minute with code 1000 and the reason call_ended, possibly without a call ended event first.
Retell -> your server event spec
Retell sends three kinds of events to your server in this WebSocket. To differentiate between them, check thetype field:
transcript_snapshot: sent once after the connection is admitted, with the whole transcript so fartranscript_updated: sent whenever the transcript changescall_ended: sent once when the call ends, right before Retell closes the connection
Transcript snapshot event
Sent once, shortly after the connection is admitted. Retell requests the snapshot from the call’s server after your connection opens, so it can arrive after the first transcript updated events.enum<string>
required
Differentiate what this event is.Available options:
transcript_snapshotobject[]
required
Every transcript item in the call so far, sorted by
time_sec. Empty if nothing has been said yet.object[]
required
Calls made by the agent’s pre-session tools before the conversation started, as
tool_call_invocation and tool_call_result items. Empty when the agent has no pre-session tools.Transcript updated event
Sent whenever the transcript changes. Each event carries one changed item. The exception is a pre-session update, wheretranscripts is empty and pre_session_transcripts carries the full pre-session list.
enum<string>
required
Differentiate what this event is.Available options:
transcript_updatedobject[]
required
The transcript item that changed, as a one-element array. An item whose id you have already seen replaces the earlier version. Empty when the event only carries
pre_session_transcripts.object[]
Present only when pre-session tool results arrive after you connect. Contains every pre-session item so far, in the same shape as the snapshot.
Call ended event
The last message before Retell closes the connection with code 1000.enum<string>
required
Differentiate what this event is.Available options:
call_endedinteger
When the call ended, in milliseconds since the Unix epoch.
string
Why the call ended, such as
user_hangup or agent_hangup. Same values as disconnection_reason in the Get Call response.Transcript item spec
Each item intranscripts and pre_session_transcripts carries the fields below, plus the fields for its role. The id is the role followed by a per-role counter, such as agent_2 or tool_call_invocation_0.
string
required
Stable id for this item. A later item with the same id replaces this one.
number
required
When the item started, in seconds from the start of the call. For
user and agent items this is the start of the first word, or 0 before any word timing exists. Sort by this field for display and keep arrival order for ties.enum<string>
required
What kind of item this is.Available options:
user, agent, tool_call_invocation, tool_call_result, node_transition, dtmf, sms, injectedUser and agent items
A spoken turn.string
required
The text of the turn so far. It grows while the speaker continues, and each change re-sends the item. When the caller’s speech couldn’t be recognized,
content is (unintelligible audio).Tool call invocation item
The agent called a tool. Match it to its result withtool_call_id.
string
required
Unique id of the tool call.
string
required
Name of the tool.
string
required
Arguments passed to the tool, as a stringified JSON object.
enum<string>
Kind of tool.Available options:
custom, code, mcp, integration_app, end_call, transfer_call, bridge_transfer, cancel_transfer, agent_swap, press_digit, send_sms, extract_dynamic_variable, adjust_voice_speed, book_appointment_cal, check_availability_calTool call result item
The tool the agent called returned.string
required
Id of the invocation this result belongs to.
string
required
What the tool returned, often a stringified JSON object.
boolean
Whether the tool call succeeded. Absent when the outcome wasn’t recorded, which doesn’t mean it failed.
Node transition item
A conversation flow agent moved to another node.string
required
Id of the node the agent left.
string
required
Name of the node the agent left.
string
required
Id of the node the agent entered.
string
required
Name of the node the agent entered.
enum<string>
required
How the node was reached:
normal for a regular edge, global for a global node, global_go_back when returning from a global node, or interrupt_go_back when returning after a user interruption.Available options: normal, global, global_go_back, interrupt_go_backDTMF item
The caller pressed a key on their phone keypad.string
required
The key pressed: a single character such as
1, *, or #.SMS item
An SMS the caller sent during the call, for example while the agent was leaving a voicemail. Not part of the spoken conversation.string
required
Text of the message.
object[]
MMS attachments. Display only.
Injected item
Context your server added mid-call with Update Live Call. Not spoken by either party.string
required
The injected text.
Close codes
Retell closes the connection with a standard WebSocket close frame. The reason text says why.Sample events
Retell -> your server sample events
Transcript item sample events
Each of these appears inside thetranscripts array of a snapshot or update. Pre-session tool calls use the same shapes inside pre_session_transcripts.
FAQ
Can I get the call audio over this WebSocket?
Can I get the call audio over this WebSocket?
No. The stream is transcript only. Live audio is available in the dashboard through Live Listen, and the recording is available from Get Call after the call ends.
Why do I get close code 4004 right after creating a call?
Why do I get close code 4004 right after creating a call?
The call hasn’t connected yet. Monitoring requires a
call_status of ongoing, and a call stays registered until the callee answers or the web client joins. Wait for the call_started webhook, or poll Get Call, then connect.Why does the same transcript item arrive more than once?
Why does the same transcript item arrive more than once?
That’s how updates work. A user or agent turn is re-sent with more text as the speaker continues, and the snapshot can overlap with updates that arrived first. Replace items by
id.Do I need to send anything on the socket?
Do I need to send anything on the socket?
No. Retell sends every event and closes the connection when the call ends. There is no config, ping, or acknowledgement to send back, unlike the LLM WebSocket.
Does this work for web calls and chats?
Does this work for web calls and chats?
Phone calls and web calls, yes. Chats aren’t calls and can’t be monitored with this WebSocket.
Can I connect from a browser?
Can I connect from a browser?
Only through your own backend. Browsers can’t set the
Authorization header on a WebSocket handshake, and your API key must stay server side. Relay the events from your server to the browser.
