Realtime
Three WebSocket endpoints. All are under /ws, not /api/ws.
| Endpoint | Direction | Auth |
|---|---|---|
/ws/agent-assist/:uuid | Provider → server (audio in) | None |
/ws/live-prompting/:uuid | Server → console (transcript, suggestions) | ?token= |
/ws/agent-notify | Server → console (call notifications) | ?token= |
Browser clients pass the session token as a query parameter, because a browser WebSocket cannot set headers.
Live prompting
wss://your-host/ws/live-prompting/<call_uuid>?token=<session-token>
Receive-only. This is the rep's panel: the transcript as it is recognised, plus the suggestions drawn from the selected knowledge base documents.
Each leg of the call is transcribed separately, so a turn is attributed to the agent or the customer rather than guessed at from one mixed stream.
The call UUID is resolved before the socket is upgraded, so an unknown one is refused with a plain HTTP error rather than an accepted socket that goes nowhere and looks like a hung panel.
| Status | Cause |
|---|---|
401 | Missing or invalid token |
404 | No such call in your organization |
Agent notifications
wss://your-host/ws/agent-notify?token=<session-token>
How a rep's panel learns that a call it did not place has started — an inbound call routed to them, or one started from a CRM side panel. The panel then opens the live-prompting socket for that call UUID.
Without this, a rep would have to poll
GET /api/calls/live/mine to notice their own
phone ringing.
Agent-assist audio
/ws/agent-assist/<call_uuid>
What the telephony provider connects to with the forked call audio. You do not call this — the provider is pointed at it by the answer webhook.
It sits outside the auth groups because Plivo cannot present a JWT. It is listen-only and addressed by an unguessable call UUID.
Exotel answers a stream request it could not match with an unmatched- address
rather than refusing it, since the customer is already on the line. That audio
is still accepted — the failure shows up as an empty panel and a log line
instead of a dropped call.
Reconnecting
There is no replay. A panel that reconnects mid-call sees events from that
point on; the stored transcript is available from
GET /api/calls/{uuid} once the call has ended.