Realtime API
Stream Realtime Call
The WebSocket of a Realtime API call: send the end user’s audio, receive Pearl’s voice and the call’s events.
GET
The second step of a Realtime API call. Create Call returns the
Always open the
Ends the call. Pearl answers with
Optional, and not answered. It only counts as activity for the 60-second
Sent once, right after you connect.
The flow’s Transfer Call node transferred the call. It is sent once Pearl has finished its transfer announcement, and is followed at once by
The call is over. Pearl then closes the connection with code
If you close the connection yourself, or it drops, nothing more arrives: the call is recorded as
url and a ticket: open url?ticket=<ticket>, for example wss://agents.nlpearl.ai/WebCall?ticket=wct_..., within 60 seconds, and the conversation runs on this connection until the call ends.
Connection
string
required
The
ticket from Create Call, starting with wct_. It is single use and valid for 60 seconds. From a server you can send it in the Authorization: Bearer wct_... header instead.url that Create Call returns rather than a fixed address. No subprotocol is needed.
A browser does not show the status of a refused connection: the socket closes at once with code
1006.
Send
What your app sends. Audio is binary, everything else is a JSON text message.Audio
20 ms of the end user’s audio, as a binary message, every 20 ms for the whole call. Start afterready.
- Raw bytes in the call’s audio format: 160 bytes in
ulaw_8000, 960 bytes inpcm_24000. - When the end user is quiet or muted, send silence frames, not nothing.
- Other frame lengths are accepted when they hold whole samples. A message may be up to 16 KB.
hangup
ended (client_hangup), then closes the connection.
ping
no_audio timer, which a client that streams audio never needs.
Unknown event types, and text that is not a JSON object with a string type, are ignored.
Receive
What Pearl sends:ready first, then audio, then at the end an optional transfer and one ended.
ready
Sent once, right after you connect.
integer
The protocol version:
1.string
The call’s id, as in the Create Call response.
object
The format of every binary message, in both directions: the same object as in the Create Call response.
Audio
20 ms of Pearl’s voice, as a binary message, every 20 ms for the whole call, with silence while it listens.- Play the frames through a small jitter buffer of 60 to 100 ms. If it grows past about 300 ms, after a network stall, drop the oldest audio.
- There is no “clear” or interruption event, and you need none: when the end user talks over Pearl, it stops speaking and the next frames are already silence.
transfer
The flow’s Transfer Call node transferred the call. It is sent once Pearl has finished its transfer announcement, and is followed at once by ended (transfer). Carrying the call on, to a person, a queue or a phone number, is up to you.
string
The destination set on your Pearl’s transfer, as entered: usually a phone number or a SIP address.
string
Why the flow transferred.
string | null
The warm-transfer message set for the receiving side.
object
SIP headers, only when the transfer is set to forward them.
object
The data Pearl has collected so far, by variable name.
ended
The call is over. Pearl then closes the connection with code 1000 and the reason as the close description.
string
Why the call ended:
integer
Whole seconds the call ran, from connection to end.
client_hangup.
Audio formats
audioFormat, chosen in Create Call, sets the format of every frame, the same in both directions. The same format has a name in each place it appears:
Limits
Versioning
ready.protocol is 1. New event types may be added within a version, which is why unknown types are ignored. A change to the frame format would raise the version.

