fonoster protocol. Each call is one
session. Both SDKs send the same session protocol messages and
have the same methods, in each language’s naming. For a walkthrough, see
Build a stream with the Voice SDK or
Use the Python Voice SDK.
VoiceServer
VoiceServer accepts Fonoster’s WebSocket connections, checks each one’s signature and runs your
handler once per call with a Session.
Options
- Node.js
- Python
new VoiceServer(options)401. In Node.js, plain HTTP requests to the listen() server get 426 WebSocket required.
Methods
The handler takes one argument, the session. In Python it must be an
async def function with
one parameter; anything else raises TypeError. If the handler throws, the SDK hangs up the call.
voice_asgi_app (Python)
voice_asgi_app(handler, *, signing_secret=None, verify_signature_=True, public_url=None) returns
an ASGI app to mount in FastAPI, Starlette or any ASGI framework:
app.mount("/voice", voice_asgi_app(on_call, signing_secret=..., public_url=...)). HTTP requests
get 426; a bad signature closes the WebSocket with code 1008. Note the trailing underscore in
verify_signature_.
Session properties
Read-only fields from the call’ssession.start message.
Session methods
Speech
SayResult
Speaks
text and resolves when it has been heard or cut off. text can be a string or an
async iterable of strings: the pieces are spoken as one utterance as they arrive. If the
iterable throws, the SDK ends the utterance and rethrows.Options: voice and language (catalog ids that override the stream’s defaults for this
utterance), interruptible (default true), preempt (stop what is playing and speak this
first). Python takes them as keyword arguments.Resolves to { interrupted, heardText, heardMs } (Python: SayResult(interrupted, heard_text, heard_ms)). heardText holds only the words the caller heard.void
Python:
stop_say(). Sends clear: every pending say and play resolves with
interrupted: true.PlayResult
Plays a WAV file from an
http or https URL. Options: loop, interruptible (default
true), preempt. Resolves to { interrupted, heardMs } (Python: PlayResult(interrupted, heard_ms)).GatherResult
Waits for speech or keypresses, whichever comes first, and resolves to
{ speech },
{ digits }, or neither when the timeout passes (Python: GatherResult(speech, digits)).Once a digit arrives, speech is ignored. Only one
gather can be pending; a second one
rejects. Speech and digits that arrive while no gather is pending are kept (up to 32) and
count toward the next one.void
Node.js only. Starts listening or changes how Fonoster listens:
language, hints (words to
favor) and patience ("low", "normal" or "high"). Sends listen.update.void
Turns on opt-in events:
"turn.estimate" and "transcript.partial".Session
Adds or removes an event listener. See Events. In Python the callback gets a dict and
can be a plain function or a coroutine. An error thrown by a listener is ignored.
Call control
void
Transfers the call to a phone number or SIP address. Options:
mode ("cold", the default,
"warm" or "refer") and headers (custom X- SIP headers). Resolves when the session ends
with reason transfer. Rejects with SessionError code transfer_failed when the target can’t
be reached. See Transfer calls.void
Python:
complete_transfer(). Connects the caller to the party of the pending warm transfer and
ends your session; resolves when the session ends. Throws if no warm transfer is pending, and
rejects with SessionError code transfer_not_answered before the transfer.answered event
(the transfer stays pending).void
Python:
play_dtmf(digits). Sends keypresses on the call: 0–9, A–D, *, #, and w
for a pause.void
Puts the caller on hold with optional
music (a URL, looped), or takes them off hold. While on
hold you get no caller audio and no turn events; keypresses still arrive.void
Hands the call to another application in the workspace, by ref. That application gets the
payload (up to 16 KB) in handoffPayload. Resolves when your session ends. At most 5 handoffs
per call.void
Hangs up and resolves when the session ends. Resolves at once if it already ended.
void
Does nothing and resolves at once. Fonoster answers the call before your handler runs.
Raw audio
session.audio sends and receives audio in the session’s audioFormat.
Events
Register listeners withsession.on(event, callback). The callback gets the event’s fields.
end reasons: caller_hangup, app_hangup, transfer, handoff, error, timeout, and
closed when the socket closed without a session.end.
Speech recognition starts with your first say, play, subscribe, listen or speech
gather. Until then there are no turn events.
Barge-in
When the caller starts talking while asay or play is being heard, and every item playing is
interruptible, the SDK sends clear and the call resolves with interrupted: true. Items sent
with interruptible: false keep playing. Fonoster itself never cuts the agent off; see
Turn-taking and barge-in.
Errors
Import both from@fonoster/voice or fonoster.voice.
Error
Fonoster rejected a command. Fields:
code, message, fatal. The codes are listed in the
session protocol. A fatal error also ends the session.Error
The session ended while a command was pending, or you sent a command after it ended. Field:
reason. Every pending say, play, gather, transfer and handoff rejects with it, so
your handler never hangs.Signature helpers
Use these to verify Fonoster’s connection signature in your own WebSocket server. See Verify request signatures.- Node.js
- Python
Exported from
@fonoster/voice: