Skip to main content
A phone call is one way to reach an agent. Realtime is the other: your user talks to the same agent from a browser tab, a mobile app or a kiosk, over a WebSocket. The engines, prompts, knowledge bases and appointment booking are the ones your phone calls use — only the line is different. Two steps, and the split is the security model:
  1. Your server calls POST /v1/realtime/sessions with your API key and gets a client_secret.
  2. Your client opens wss://api.phone.wixzel.com/v1/realtime?client_secret=… and streams audio.
The secret works once, for one minute, for one agent. Your API key never leaves your server.

1. Create a session (server)

Response
Needs the calls:write scope. Nothing is charged here — a user who opens your page and then denies the microphone costs you nothing.

2. Connect (client)

In a browser

The TypeScript SDK ships a browser client that handles the microphone, encoding, playback and barge-in:
It needs a secure page (https://, or localhost) and asks for the microphone when connect is called. To ask before you mint a session, call requestMicrophone() first and pass the stream to session.start().

In Flutter or Dart

The Dart SDK has the protocol client. Microphone and speaker access are your app’s — use any recording plugin that gives you 16-bit PCM at 8 kHz, and any PCM player:
Turn on your platform’s echo cancellation. Without it the agent hears itself through the speaker and interrupts itself.

Anything else

The protocol is plain JSON over a WebSocket, below.

The protocol

Every frame is a JSON text message with a type. Audio is base64 G.711 µ-law, 8 kHz, mono in both directions — exactly what a phone line carries. Send it in 20 ms frames (160 bytes). From the server From the client While the agent is saying its opening line, keep sending audio but send silence (0xFF bytes): the agent then cannot be interrupted by room noise before the user has heard anything. The browser client does this for you.

Why a session ends

Refusals

A browser cannot read the HTTP status of a refused WebSocket, so refusals arrive as an error frame followed by a close with one of these codes:

Billing and records

A realtime session is a call to everything but the phone network:
  • It is billed at the same per-minute price as a phone call on the same engine, per second, from credit. See pricing.
  • It counts toward your concurrent-call limit (5 by default) and the API key’s spend limit.
  • It appears in GET /v1/calls with "channel": "web" (filter with ?channel=web), inbound, with no from or to, and with its transcript.
  • It ends with a callCompleted webhook carrying "provider": "web" and your metadata.
Human transfer is not available: there is no second line to hand the user to. Web sessions are not recorded.