Pipecat
Run a Pipecat bot on Vonyx calls through LiveKit SIP.
A Pipecat bot can make and take calls on your Vonyx number. Vonyx connects to LiveKit SIP over your SIP trunk, and the bot joins the call's LiveKit room with Pipecat's LiveKitTransport.
Why LiveKit, not Daily or a WebSocket serializer
Pipecat's Daily SIP route doesn't fit a username/password trunk: Daily's sipUri dial-out has no field for SIP credentials, and Daily dial-in expects the carrier to forward each call to a per-room SIP URI, while Vonyx forwards to one fixed inbound address. Pipecat's Twilio, Telnyx, Plivo and Exotel serializers only speak those providers' WebSocket formats. If you already run Asterisk on Vonyx, Pipecat lists a community-maintained Asterisk serializer (pipecat-asterisk) that Pipecat doesn't test or support. A native Vonyx WebSocket route for Pipecat is coming.
Before you start
- A Vonyx SIP trunk with a number attached
- A LiveKit Cloud project with its
LIVEKIT_URL,LIVEKIT_API_KEYandLIVEKIT_API_SECRET - The LiveKit CLI signed in to that project
- Python with Pipecat and the LiveKit extra, plus keys for your STT, LLM and TTS services
Write the bot
One bot file serves both directions. It joins a LiveKit room as a participant. With a number to dial, it places the call itself and greets the callee once they answer. Without one, it waits for the caller who is already in the room.
Dialling waits for the answer (wait_until_answered=True) before the greeting, so the callee doesn't miss it while the phone rings.
Outbound calls
Create the LiveKit outbound trunk
Follow Outbound calls in the LiveKit guide to create an outbound trunk with your Vonyx address, trunk username, password and number. Put its trunk ID (ST_…) in LIVEKIT_SIP_TRUNK_ID.
Start the bot with a number
The bot joins a new room, LiveKit dials the number through Vonyx, and the bot speaks once the callee answers. The callee sees the Vonyx number on the outbound trunk as caller ID. To use a different one of your Vonyx numbers per call, set sip_number on the CreateSIPParticipantRequest.
Inbound calls
LiveKit SIP creates a room for each call. A Pipecat bot isn't a LiveKit Agents worker, so LiveKit can't dispatch it. Instead, a LiveKit webhook tells your server when a call room starts, and the server runs the bot in it.
Create the inbound trunk and point Vonyx at it
Follow Inbound calls in the LiveKit guide to find your LiveKit SIP endpoint, create the inbound trunk and set it as the trunk's inbound address in the Vonyx console. Skip that guide's dispatch rule and use the one below.
Add a dispatch rule without an agent
This rule puts each caller in a new room prefixed call-. It has no room_config.agents, because your webhook starts the bot.
Run a webhook server
The server checks LiveKit's signature, then starts the bot for every room_started event on a call- room. Outbound rooms use the out- prefix, so they are ignored.
The server must be reachable from the internet (for local testing, use a tunnel).
Register the webhook in LiveKit Cloud
In LiveKit Cloud, open Settings → Webhooks → Create new webhook. Enter a Name, set the URL to https://your-server.example.com/livekit/webhook, pick the Signing API key that matches LIVEKIT_API_KEY, and select Create.
Hang up from the bot
Stopping the pipeline only takes the bot out of the room; the caller would hear silence. To end the call, delete the room:
Test the connection
- Trunk first: check that
lk sip participant createreaches your phone, as in the LiveKit guide. That rules out trunk problems before the bot is involved. - Outbound: run
python call.pywith your own phone number. Your phone should ring with your Vonyx number, and the bot should greet you when you answer. - Inbound: with
server.pyrunning and the webhook registered, call your Vonyx number. Acall-…room should appear in LiveKit Cloud with a SIP participant andPipecat Bot, and the bot should greet you.
Limitations
- DTMF and call transfer are not available on Vonyx yet. Don't rely on Pipecat's
on_dtmf_event,OutputDTMFFrameorDTMFAggregator, or on LiveKit SIP transfers. - New accounts make 1 call at a time (raise limits).
- Codecs are PCMU and PCMA only, with no TLS or SRTP. LiveKit SIP handles the conversion to WebRTC audio for the bot.
- Caller ID must be one of your Vonyx numbers.
- The bot code above runs one bot per call inside the webhook server's process. Under real traffic, run bots as separate processes or jobs.
Troubleshooting
| Problem | Fix |
|---|---|
Call failed: 401 or 407 | The trunk username or password on the LiveKit outbound trunk is wrong. |
Call failed: 486 or 603 | The callee rejected the call. |
Call failed: 408 or 480 | No answer, or the callee was unreachable. |
| Outbound call rejected right away | Check the outbound trunk's number is one of your Vonyx numbers and the dialled number is 91XXXXXXXXXX. |
| The callee hears nothing after answering | Check the bot logs for STT, LLM or TTS key errors. The greeting is only queued after wait_until_answered returns. |
| Inbound room appears but the bot never joins | The webhook isn't reaching server.py, the signature check fails (wrong signing key), or the room name doesn't start with call-. Use Send a test event on the webhook in LiveKit Cloud. |
| Inbound call never reaches LiveKit | Check Inbound calls is on and the inbound address has no sip: prefix. See the LiveKit guide. |
| Caller hears silence after the bot stops | Delete the room to hang up (see Hang up from the bot). |
| Second parallel call fails | New accounts have 1 channel. See limits. |
| Call connects with no audio | See SIP troubleshooting. Vonyx sends RTP over UDP 10000–20000. |