Skip to main content
The Python Voice SDK (fonoster-voice) answers calls for a stream that speaks the fonoster protocol. It has the same session and the same verbs as the Node.js SDK, in Python naming. Use it to put your Python agent code, or your model calls, on the phone. This page assumes you already have a stream and its signing secret. If not, Build a stream with the Voice SDK shows how to create one and expose your machine with a tunnel.

Install the SDK

Install the package from PyPI. It needs Python 3.11 or later, and its only dependency is websockets:
The SDK is asyncio only. Handlers must be async def functions that take one argument, the session. The SDK raises TypeError for anything else.

Run a standalone server

Use VoiceServer when the voice server is its own process. This one greets the caller, listens for speech or a keypress, and transfers to a person on request:
server.py
Run it with your stream’s signing secret and its URL:
server.run() blocks and serves until you stop it. Inside your own event loop, call await server.listen() instead; it returns once the server is listening. VoiceServer takes these options:
Always set public_url when a tunnel, load balancer or proxy sits in front of your server. Without it, the SDK rebuilds the URL from the request’s Host header, which may not match the URL Fonoster signed. See Verify request signatures.

Mount it in FastAPI

To serve calls from an app you already run, mount voice_asgi_app on a path. It works with FastAPI, Starlette and any other ASGI framework:
main.py
Run the app with any ASGI server:
Set the stream’s URL to the mounted path, here wss://bot.example.com/voice, and pass that same URL as public_url. Plain HTTP requests to the path get 426 WebSocket required.

Stream model output into speech

Pass an async iterator to say() and the caller hears the text as it arrives, as one continuous utterance. You don’t wait for the full reply before the caller hears the first words. This example streams a reply from an OpenAI-compatible model:
If the iterator raises, the SDK ends the utterance and re-raises the error in your handler.

Handle barge-in

By default the caller can talk over the agent. When they start talking during a say() or play(), the SDK stops the speech, and say() returns with interrupted=True. heard_text holds only the words the caller actually heard:
Pass interruptible=False for text the caller must hear in full, such as a legal notice. The caller can still talk; what they say is kept for the next gather():
To cut the agent off yourself, call await session.stop_say(). Every pending say() and play() returns as interrupted. Speech and keypresses that arrive before you call gather() are kept (up to 32), so callers can answer before the question ends.
When the caller stops talking is decided by Fonoster’s turn detector, not by silence alone. See Turn-taking and barge-in.

Listen to events

Register callbacks with session.on(event, callback). The callback gets the event’s fields as a dict, and it can be a plain function or a coroutine:
Two events are opt-in. Ask for interim transcripts or the turn detector’s estimate with subscribe():
The Voice SDK reference lists every event and its fields.

Handle errors

  • When Fonoster rejects a command, the call raises SessionError with code, message and fatal. A failed transfer raises SessionError with code transfer_failed.
  • When the call ends while a command is pending, it raises SessionEndedError with reason, so your handler never hangs.
  • If your handler raises, the SDK hangs up the call instead of leaving the caller in silence.
Import both errors from fonoster.voice.

How the Python SDK differs from Node.js

The verbs and results are the same. The names follow Python style: Both SDKs speak the same wire format: see the session protocol.

Next steps

Verify request signatures

What the SDK checks, and how to rotate the secret.

Voice SDK reference

Every method, option and event in Node.js and Python.

Bring your Twilio or Pipecat app

Already have a Pipecat bot? Run it unchanged.

Transfer calls

Cold, warm and SIP REFER transfers.