Skip to main content

Overview

BandwidthFrameSerializer is a FrameSerializer that converts between Pipecat frames and Bandwidth Programmable Voice’s bidirectional WebSocket media stream protocol. Plug it into a FastAPIWebsocketTransport to use Bandwidth as the telephony layer for your Pipecat voice bots.

Source Repository

Source code, examples, and issues for the Bandwidth integration

PyPI Package

The pipecat-bandwidth package on PyPI

Bandwidth StartStream BXML

Bandwidth’s media-stream protocol reference

Bandwidth Voice API

Manage credentials and calls via the Bandwidth Voice API

Installation

This is a community-maintained package distributed separately from pipecat-ai:
uv add pipecat-bandwidth

Prerequisites

Bandwidth Account Setup

Before using BandwidthFrameSerializer, you need:
  1. Bandwidth Account: Sign up at Bandwidth
  2. Programmable Voice: A phone number and application configured for Programmable Voice with a <StartStream mode="bidirectional"> BXML response
  3. OAuth 2.0 Credentials: A Client ID and Client Secret for the Bandwidth Voice API (required for auto hang-up)

Required Environment Variables

  • BANDWIDTH_CLIENT_ID: OAuth 2.0 Client ID for Bandwidth API authentication
  • BANDWIDTH_CLIENT_SECRET: OAuth 2.0 Client Secret for Bandwidth API authentication
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 metadata, which is unauthenticated and attacker-controllable.

Configuration

stream_id
str
required
The Bandwidth Stream ID, available in the start event metadata.
call_id
str
default:"None"
The Bandwidth Call ID. Required when auto_hang_up is enabled. Must come from a server-trusted source (e.g. the signed inbound voice webhook).
account_id
str
default:"None"
The Bandwidth account ID. Required when auto_hang_up is enabled. Same trust requirement as call_id.
client_id
str
default:"None"
OAuth 2.0 Client ID for Bandwidth API authentication. Required when auto_hang_up is enabled.
client_secret
str
default:"None"
OAuth 2.0 Client Secret for Bandwidth API authentication. Required when auto_hang_up is enabled.
params
InputParams
default:"None"
Configuration parameters for audio encoding and hang-up behavior. See InputParams below.

InputParams

Configuration passed via the params constructor argument using BandwidthFrameSerializer.InputParams(...).
ParameterTypeDefaultDescription
bandwidth_sample_rateint8000Sample rate Bandwidth uses on the wire for PCMU audio. Always 8000 Hz; exposed for symmetry with other serializers.
sample_rateintNoneOptional override for the pipeline input sample rate.
outbound_encodingstr"PCMU"Audio encoding for media sent back to the call: "PCMU" (μ-law 8 kHz) or "PCM" (16-bit signed little-endian PCM).
outbound_pcm_sample_rateint24000Sample rate used when outbound_encoding == "PCM". One of 8000, 16000, or 24000. Higher improves TTS quality.
auto_hang_upboolTrueWhether to automatically terminate the call via the Voice API on EndFrame or CancelFrame.
ignore_rtvi_messagesboolFalseInherited from the base FrameSerializer.

Usage

Wire the serializer into a FastAPIWebsocketTransport:
import os

from pipecat.transports.websocket.fastapi import (
    FastAPIWebsocketParams,
    FastAPIWebsocketTransport,
)
from pipecat_bandwidth import BandwidthFrameSerializer

# call_id and account_id MUST come from a server-trusted source — typically
# the authenticated inbound voice webhook body — not the WebSocket "start"
# event metadata.
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,
    ),
)
DTMF is not delivered over the media-stream WebSocket on Bandwidth. It is captured by the BXML <Gather> verb and posted to a separate webhook, so DTMF handling belongs in your application’s webhook handler, not the serializer.

Compatibility

Tested with Pipecat v1.4.0. Check the source repository for the latest tested version and changelog.