Guides

Browser voice test

Talk to an agent from a browser tab, with the real voice pipeline and no phone call.

A browser voice test is a real conversation with an agent through your microphone and speakers. It uses the own voice engine with everything a phone call uses: speech detection, interruption, graph routing, function tools, knowledge bases, recording and redaction. Nothing is dialled and there is no telephony charge.

In the dashboard: Agent Studio, the Talk to agent button. This page explains the two steps behind it so you can build the same thing.

Note: This needs the own voice engine running, with its speech-to-text, LLM and text-to-speech backends configured by the operator, and reachable from your browser. It does not work with the mock engine. For tests with no engine at all, see Testing without a phone.

Step 1: get a ticket

bash
curl -X POST https://api.sevennadi.si/agent-voice-test/3c90c3cc-0d44-4b50-8822-8dd25736052a \
  -H "Authorization: Bearer vs-0123456789abcdef0123456789abcdef"
json
{"ws_url": "wss://voice.sevennadi.si/web", "token": "MTIzNDU2Nzg...", "expires_in": 120}
  • ws_url is the engine's browser endpoint, as the operator configured it. On a default local install it is ws://127.0.0.1:9140/web.
  • token is signed, names your account and this agent, works once, and must be used within expires_in seconds (120).
  • An unknown agent is 404 Agent not found.

Step 2: open the WebSocket

javascript
const ws = new WebSocket(ticket.ws_url);
ws.binaryType = "arraybuffer";

ws.onopen = () => {
  ws.send(JSON.stringify({ type: "start", token: ticket.token, sample_rate: 16000 }));
};

ws.onmessage = (event) => {
  if (typeof event.data !== "string") {
    playPcm16(event.data);            // 16-bit mono PCM at the rate given in "ready"
    return;
  }
  const message = JSON.parse(event.data);
  if (message.type === "ready") startMicrophone(ws);
  if (message.type === "clear") dropQueuedAudio();   // the caller interrupted the agent
  if (message.type === "end") ws.close();
};

playPcm16, startMicrophone and dropQueuedAudio are yours to write; the dashboard uses audio worklets for capture and playback.

The first message must be start. The engine redeems the token with the platform, which creates the call record and returns the agent's session. Then the engine answers:

json
{"type": "ready", "execution_id": "b8f0c9a2-3e5d-4c1b-9f7a-2d6e8c4b1a90", "sample_rate": 24000, "max_seconds": 300, "node": null}

Audio

DirectionFormat
Browser to engineBinary frames of 16-bit mono PCM at the sample_rate you sent in start (8,000 to 48,000 Hz; 16,000 is normal)
Engine to browserBinary frames of 16-bit mono PCM at the sample_rate in ready (24,000 Hz by default), 20 ms each

Messages from the page

MessageMeaning
{"type": "start", "token": "...", "sample_rate": 16000}First message
{"type": "dtmf", "digit": "5"}A keypad press
{"type": "stop"}Hang up

Messages from the engine

MessageMeaning
{"type": "ready", ...}The call has started
{"type": "clear"}Drop all queued audio now
{"type": "speaking", "text", "style"}A sentence is about to be spoken
{"type": "turn", "role", "text"}A finished turn of either side, as it is stored (PII masked)
{"type": "node", "id", "name", "path"}Graph agents: the current node
{"type": "tool", "name", "status"}A tool call finished: success or error
{"type": "error", "status", "message"}The call could not start
{"type": "end", "reason", "code", "execution_id"}The call is over; the socket closes next

Close codes

CodeMeaning
4401Bad, expired or already used token
4429A voice test is already running for this account

A page from an origin the engine does not allow is refused with HTTP 403 before the socket opens.

What the browser needs

  • Microphone permission. Browsers grant it only on secure pages: https, or localhost during development.
  • WebSocket support, with binary frames.
  • A way to capture and play raw PCM. The dashboard requires AudioWorklet and getUserMedia and tells the user when they are missing.
  • Echo handling. Capture with echoCancellation, noiseSuppression and autoGainControl switched on. The engine keeps its own echo guard on too, because laptop speakers leak into the microphone.
  • An allowed origin. The operator lists the origins that may connect. By default only the local dashboard addresses are allowed.
  • If the page is served over https, ws_url must be wss://.

The call record

A test call is an ordinary execution, so it appears in Call History and in the API:

FieldValue
call_typeinbound
telephony_data.providerweb
agent_numberweb
context_details.web_calltrue
cost_breakdown.network0

It has a transcript, a recording, tool call logs, a graph path and the usual cost for the speech, LLM and voice components plus the platform fee. Webhooks fire as for any call. See Post-call data.

To end a test from the server side, call POST /call/{execution_id}/stop with the execution_id from ready.

Limits

LimitValue
Ticket lifetime120 seconds, single use
Simultaneous testsOne per account. A second ticket is issued, but its connection is refused
Call length300 seconds by default (max_seconds in ready), set by the operator

Limitations

  • A browser test is not a phone call. Audio is wide-band and the network path is different, so latency, audio quality and speech recognition can differ from what a caller on a phone line gets.
  • The engine has an echo guard, not echo cancellation. It has been tested on simulated echo.
  • Speech recognition is not streaming: the engine waits for the end of an utterance, so there are no partial transcripts.
  • Test calls are charged for the model components and the platform fee.

Protocol details for engine developers are in Engine protocol and the endpoint is in Voice test reference.