Protocol

The following sequence applies to every call. Fonada acts as the WebSocket client; your endpoint acts as the WebSocket server.

StepPartyAction
1FonadaThe call is answered (inbound) or the end user answers (outbound).
2FonadaFonada opens a WebSocket connection to your URL.
3YouYour endpoint accepts the upgrade (HTTP 101).
4FonadaFonada sends session_start with call context and audio settings.
5YouYour endpoint optionally replies with ready.
6BothBidirectional audio streaming takes place.
7EitherThe call ends, or it is transferred to a human agent.
  • One connection per call. Connections are not pooled or reused, so 200 calls result in 200 connect-and-disconnect cycles.
  • Fonada begins sending audio immediately after session_start and does not wait for ready. If your service needs warm-up time, accept the connection and buffer incoming audio rather than delaying the accept.
  • session_start always arrives first, as a single text frame, before any audio.

session_start — text, once per call

{
  "type": "session_start",
  "session_id": "1711234567.42",
  "client_id": "acme-voicebot",
  "customer_phone": "919876543210",
  "business_phone": "18001234567",
  "audio": {
    "codec": "pcm16",
    "input_sample_rate": 16000,
    "output_sample_rate": 16000,
    "channels": 1
  },
  "metadata": {
    "language": "en",
    "agent_id": "sales-agent-v2"
  }
}
FieldDescription
session_idUnique call identifier. Log and retain it — it correlates your logs with Fonada's during support, and it is the key passed to the transfer API.
client_idYour configuration name on the Fonada platform. Useful where a single endpoint serves several campaigns or brands.
customer_phoneThe end user. See Call flows for inbound vs outbound roles.
business_phoneYour platform number.
audio.codecAlways pcm16 unless otherwise agreed: signed 16-bit little-endian PCM.
audio.input_sample_rateSample rate of the audio Fonada sends to you.
audio.output_sample_rateSample rate Fonada expects you to send back.
audio.channelsAlways 1 (mono).
metadataAgreed key/value pairs — language, agent or prompt identifier, campaign reference. Configurable per account.

The call-direction value is delivered here too, under the field name you choose. Only type and audio are fixed; every other field name is configurable, and Fonada can add fields. See Customisation.

End-user audio — continuous

The end user's voice is delivered as raw PCM16 little-endian mono audio at input_sample_rate. By default these are binary WebSocket frames containing nothing but audio samples — no header, no wrapper. If your stack cannot handle binary frames, Fonada can send base64 text frames instead; see Audio.

The frame (chunk) size is configurable and determines how often a frame is received:

Chunk sizeAt 8 kHzAt 16 kHzSuitability
320 bytesevery 20 msevery 10 msStreaming ASR, barge-in detection
640 bytesevery 40 msevery 20 msStreaming ASR (common choice)
1280 bytesevery 80 msevery 40 msBalanced
16384 bytesevery 1024 msevery 512 msBatch processing only (Fonada default)

Audio arrives at approximately real-time pace for the whole call, including during silence — silence is delivered as PCM silence, not as an absence of frames.

playback_completed — text

{ "type": "playback_completed" }

Sent once everything you provided for the current turn has finished playing to the end user. Use it to know the end user is now hearing silence and to begin listening for the next utterance.

session_end — text

{ "type": "session_end" }

The call is ending from Fonada's side — most commonly because the end user hung up. Immediately afterwards Fonada sends a WebSocket close frame (code 1000) and closes the socket. Release per-call resources when this message is received.

Messages you send

All messages in this section are optional. Audio flows in both directions with no control messages at all — a minimal endpoint can accept the connection, read audio, and write audio back. The control messages enable interruption handling and precise turn boundaries.

  1. Fonada sends session_start.
  2. You optionally send ready.
  3. Fonada streams caller audio continuously.
  4. You send TTS audio (media).
  5. You send end_of_generation.
  6. Fonada sends playback_completed.

ready — optional

{ "type": "ready" }

Acknowledges session_start. Informational; Fonada logs it and continues.

end_of_generation — optional

{ "type": "end_of_generation" }

Signals that everything for the current turn has been sent. This is what lets Fonada emit playback_completed once your audio finishes playing. Without it, turn boundaries are not signalled back to you.

end_of_call — optional

{ "type": "end_of_call" }

Requests that Fonada end the call, for example after a goodbye message. Fonada lets any remaining audio finish playing first and then hangs up. If you have sent no audio at all, Fonada hangs up immediately.

error — optional

{ "type": "error", "message": "ASR model unavailable", "code": "asr_error" }

Reports a problem on your side. Fonada logs it for diagnostics but takes no action, and the call continues. To terminate the call, send end_of_call or close the WebSocket (which also ends the call).