A Pipecat community integration that lets you use Bandwidth Programmable Voice as the telephony layer for your Pipecat voice bots.
This package provides BandwidthFrameSerializer, a FrameSerializer you plug
into a FastAPIWebsocketTransport to handle Bandwidth's bidirectional
WebSocket media stream protocol.
Maintained by Bandwidth.
- Decodes Bandwidth's inbound μ-law audio (8 kHz) into Pipecat audio frames.
- Encodes outbound audio as either μ-law or linear PCM at 8/16/24 kHz. PCM at 24 kHz noticeably improves TTS quality compared to μ-law.
- Handles interruptions by emitting Bandwidth's
clearevent, so the bot stops talking immediately when the caller speaks. - Auto hangs up the call via the Bandwidth Voice API on
EndFrameorCancelFrame, using OAuth 2.0 client_credentials.
pip install pipecat-bandwidthOr with uv:
uv add pipecat-bandwidthfrom pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from pipecat_bandwidth import BandwidthFrameSerializer
# IMPORTANT: call_id and account_id flow into an authenticated POST to the
# Bandwidth Voice API on auto hang-up. They MUST come from a server-trusted
# source — typically the (authenticated) inbound voice webhook body — and
# NOT from the WebSocket "start" event's metadata, which is unauthenticated
# and attacker-controllable. See the chatbot example for one safe pattern
# (token-in-URL correlating the webhook to the WS connect).
serializer = BandwidthFrameSerializer(
stream_id=stream_id,
call_id=call_id,
account_id=account_id,
client_id=os.getenv("BANDWIDTH_CLIENT_ID"),
client_secret=os.getenv("BANDWIDTH_CLIENT_SECRET"),
)
transport = FastAPIWebsocketTransport(
websocket=websocket,
params=FastAPIWebsocketParams(
audio_in_enabled=True,
audio_out_enabled=True,
add_wav_header=False,
serializer=serializer,
),
)For higher-fidelity outbound audio, configure linear PCM:
from pipecat_bandwidth import BandwidthFrameSerializer
serializer = BandwidthFrameSerializer(
stream_id=stream_id,
call_id=call_id,
account_id=account_id,
client_id=os.getenv("BANDWIDTH_CLIENT_ID"),
client_secret=os.getenv("BANDWIDTH_CLIENT_SECRET"),
params=BandwidthFrameSerializer.InputParams(
outbound_encoding="PCM",
outbound_pcm_sample_rate=24000,
),
)A complete end-to-end example lives in
examples/bandwidth-chatbot. It shows a
single-file FastAPI server that:
- Returns a
<StartStream>BXML response on Bandwidth's voice webhook. - Accepts the bidirectional WebSocket and reads Bandwidth's
startevent for the stream/call/account IDs. - Runs a Deepgram (STT) → OpenAI (LLM) → Cartesia (TTS) Pipecat pipeline.
The example directory also includes bot_realtime.py, a speech-to-speech
variant that runs the call on OpenAI's Realtime model — STT, LLM, and TTS
collapse into a single service, so it needs only an OpenAI API key on the
AI side (no Deepgram or Cartesia).
See the example's README for setup and run instructions.
Bandwidth does not deliver DTMF over the media-stream WebSocket. DTMF is
captured by the BXML <Gather> verb and posted to a separate webhook. Wire
DTMF handling in your application's webhook handler — not in the serializer.
- Tested with Pipecat v1.4.0.
- Python 3.11, 3.12.
BSD 2-Clause. See LICENSE.
Issues and PRs are welcome. For larger changes, please open an issue first to discuss what you'd like to change.