> ## Documentation Index
> Fetch the complete documentation index at: https://daily-hush-pcc-session-recordings-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Plivo WebSocket Integration

> Complete guide to using Plivo Media Streaming with Pipecat for dial-in and dial-out functionality

## Things you'll need

* An active [Plivo](https://www.plivo.com) account with API credentials
* One or more Plivo provisioned phone numbers
* A public-facing server or tunneling service like [ngrok](https://ngrok.com/)
* API keys for speech-to-text, text-to-speech, and LLM services

<CardGroup cols={2}>
  <Card title="Plivo Dial-in Example" icon="phone-arrow-down-left" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/plivo-chatbot/inbound">
    Complete dial-in implementation using Plivo Media Streaming over WebSocket
  </Card>

  <Card title="Plivo Dial-out Example" icon="phone-arrow-up-right" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/plivo-chatbot/outbound">
    Outbound calling using Plivo Media Streaming with WebSocket transport
  </Card>
</CardGroup>

## Phone Number Setup

You'll need Plivo phone numbers for both dial-in and dial-out functionality:

* Visit [plivo.com](https://www.plivo.com) and purchase phone numbers
* Ensure your numbers support Voice capabilities
* Configure XML applications for dial-in numbers (covered below)

## Environment Setup

Configure your environment variables for Plivo and AI services:

```shell .env theme={null}
PLIVO_AUTH_ID=...
PLIVO_AUTH_TOKEN=...
OPENAI_API_KEY=...
DEEPGRAM_API_KEY=...
CARTESIA_API_KEY=...
```

## Dial-in

Dial-in allows users to call your Plivo number and connect to your Pipecat bot via WebSocket Media Streaming.

### How It Works

Here's the sequence of events when someone calls your Plivo number:

1. **Plivo receives an incoming call** to your phone number
2. **Plivo calls your XML server** with call details
3. **Your server responds with XML** that establishes a WebSocket connection
4. **Plivo opens a WebSocket** to your server with real-time audio
5. **Your bot processes the audio** using the Pipecat pipeline
6. **The bot responds with audio** sent back to Plivo over WebSocket
7. **Plivo plays the audio** to the caller in real-time

### Set up your XML server

Your server handles Plivo webhooks and WebSocket connections for real-time audio streaming. When Plivo receives a call, your server:

1. **Receives the webhook** with call details (CallUUID, caller information)
2. **Returns XML** that establishes a WebSocket connection to your server
3. **Accepts the WebSocket** connection from Plivo
4. **Parses call data** from the WebSocket messages
5. **Runs the Pipecat bot** with the parsed call information

The server orchestrates the real-time audio streaming between Plivo's telephony infrastructure and your Pipecat bot pipeline.

### Custom Data with Query Parameters

You can pass custom data to your bot by adding query parameters to the WebSocket URL in your XML response. This works for both dial-in and dial-out scenarios:

```python server.py theme={null}
# Example: Adding custom parameters to the WebSocket URL
xml = f"""<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Stream bidirectional="true" keepCallAlive="true" contentType="audio/x-mulaw;rate=8000">
    wss://your-server.com/ws?user_id={user_id}&amp;session_type=support&amp;campaign_id=summer_sale
  </Stream>
</Response>"""
```

These parameters are accessible in your server code and can be used to customize your bot's behavior based on the specific call context.

<Card title="Complete Server Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/blob/main/plivo-chatbot/inbound/server.py">
  See the full FastAPI server code with XML generation and WebSocket handling
</Card>

### Configure your Pipecat bot for dial-in

Your bot receives the WebSocket connection and parses the call data to extract call information. The key components are:

**WebSocket Parsing**: Pipecat's built-in parser extracts call data from Plivo's WebSocket messages:

```python bot.py theme={null}
from pipecat.runner.utils import parse_telephony_websocket

async def run_bot(websocket: WebSocket):
    # Parse Plivo WebSocket data
    transport_type, call_data = await parse_telephony_websocket(websocket)

    # Extract call information
    stream_id = call_data["stream_id"]
    call_id = call_data["call_id"]  # Plivo's CallUUID
```

**Transport Creation**: Configure the WebSocket transport with Plivo serialization:

```python bot.py theme={null}
# Create Plivo serializer with call details
serializer = PlivoFrameSerializer(
    stream_id=stream_id,
    call_id=call_id,
    auth_id=os.getenv("PLIVO_AUTH_ID"),
    auth_token=os.getenv("PLIVO_AUTH_TOKEN"),
)

# Configure WebSocket transport
transport = FastAPIWebsocketTransport(
    websocket=websocket,
    params=FastAPIWebsocketParams(
        audio_in_enabled=True,
        audio_out_enabled=True,
        add_wav_header=False,
        serializer=serializer,
    ),
)

# Your bot pipeline setup here...
```

<Card title="Complete Bot Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/blob/main/plivo-chatbot/inbound/bot.py">
  See the full bot.py with WebSocket parsing, transport setup, and pipeline
  configuration
</Card>

### Set up Plivo XML application

Configure your Plivo phone number to use your XML application:

1. Go to the [Plivo Console](https://console.plivo.com)
2. Navigate to Voice → XML Applications
3. Create a new XML Application with your server's webhook URL
4. Assign the XML Application to your phone number

### Run the Example

For local development, use [ngrok](https://ngrok.com/) to expose your local server:

```shell theme={null}
# Start your server
python server.py

# In another terminal, start ngrok
ngrok http 8000

# Use the ngrok URL in your Plivo XML Application
```

<Card title="Complete Setup Instructions" icon="book-open" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/plivo-chatbot/inbound">
  See the full README with step-by-step setup, XML configuration, and testing
</Card>

## Dial-out

Dial-out allows your bot to initiate calls to phone numbers using Plivo's outbound calling capabilities with WebSocket Media Streaming.

### How It Works

Here's the sequence of events for dial-out calls:

1. **Your application triggers a dial-out** (via API call or user action)
2. **Server initiates a Plivo call** to the target phone number
3. **Plivo establishes the call** and opens a WebSocket connection
4. **Your bot joins the WebSocket** and sets up the pipeline
5. **The recipient answers** and is connected to your bot
6. **The bot handles the conversation** with real-time audio streaming

### Set up your server for dial-out

The dial-out server creates outbound calls and manages WebSocket connections. When you trigger a dial-out call, your server:

1. **Receives the dial-out request** with target phone number and parameters
2. **Creates a Plivo call** using the Voice API with XML that establishes WebSocket
3. **Accepts the WebSocket** connection from Plivo
4. **Parses call data** from the WebSocket messages
5. **Runs the Pipecat bot** with the call information

<Card title="Complete Server Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/blob/main/plivo-chatbot/outbound/server.py">
  See the full FastAPI server code with outbound call creation and WebSocket
  handling
</Card>

### Passing Custom Data to Your Bot

For dial-out calls, you often need to pass custom data to personalize the conversation—such as user information, campaign details, or context from your application. The dial-out example supports passing a `body` object that becomes available to your bot via `runner_args.body`.

**Triggering a call with custom data:**

```bash theme={null}
curl -X POST https://your-server.com/start \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+1234567890",
    "body": {
      "user": {
        "id": "user123",
        "firstName": "John",
        "lastName": "Doe",
        "accountType": "premium"
      },
      "campaign": "renewal_reminder",
      "context": "subscription expiring in 3 days"
    }
  }'
```

**How it works:**

1. The `/start` endpoint receives the request with `phone_number` and optional `body`
2. The `body` is base64-encoded and passed through the TeXML URL chain
3. When the WebSocket connects, the server decodes the body and passes it to your bot via `runner_args.body`
4. Your bot accesses the custom data to personalize the conversation

**Accessing custom data in your bot:**

```python bot.py theme={null}
async def bot(runner_args: RunnerArguments):
    body_data = runner_args.body or {}
    first_name = body_data.get("user", {}).get("firstName", "there")
    # Use first_name to personalize greetings, prompts, etc.
```

This approach works consistently in both local development and Pipecat Cloud production deployments.

### Configure your Pipecat bot for dial-out

The dial-out bot configuration is similar to dial-in, with Plivo automatically providing call information.

**Call Information**: Extract call details from Plivo's WebSocket messages:

```python bot.py theme={null}
# Parse WebSocket data (same as dial-in)
transport_type, call_data = await parse_telephony_websocket(websocket)

# Extract call information
stream_id = call_data["stream_id"]
call_id = call_data["call_id"]  # Plivo's CallUUID

# Access custom data from runner args
body_data = runner_args.body or {}
user_name = body_data.get("user", {}).get("firstName", "there")

# Customize bot behavior for outbound calls
greeting = f"Hi {user_name}! This is an automated call. How can I help you today?"
```

**Transport Configuration**: Same transport setup as dial-in:

```python bot.py theme={null}
# Create Plivo serializer
serializer = PlivoFrameSerializer(
    stream_id=stream_id,
    call_id=call_id,
    auth_id=os.getenv("PLIVO_AUTH_ID"),
    auth_token=os.getenv("PLIVO_AUTH_TOKEN"),
)

# Configure transport
transport = FastAPIWebsocketTransport(
    websocket=websocket,
    params=FastAPIWebsocketParams(
        audio_in_enabled=True,
        audio_out_enabled=True,
        add_wav_header=False,
        serializer=serializer,
    ),
)
```

<Card title="Complete Bot Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/blob/main/plivo-chatbot/outbound/bot.py">
  See the full bot.py with outbound call handling and call information usage
</Card>

### Run the Example

To test dial-out functionality:

1. **Start your server**: Run your FastAPI server
2. **Trigger a call**: Make an API request to start an outbound call
3. **Answer your phone**: The bot will call the specified number
4. **Talk to your bot**: Have a conversation with your AI agent

<Card title="Complete Setup Instructions" icon="book-open" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/plivo-chatbot/outbound">
  See the full README with step-by-step setup, API usage, and outbound call
  configuration
</Card>

## Key Features

### Audio Format and Sample Rate

Plivo Media Streaming uses 8kHz mono audio with μ-law encoding. Configure your pipeline accordingly:

```python theme={null}
worker = PipelineWorker(
    pipeline,
    params=PipelineParams(
        audio_in_sample_rate=8000,
        audio_out_sample_rate=8000,
    ),
)
```

### Automatic Call Termination

`PlivoFrameSerializer` ends the call when your pipeline ends. This is on by default (`auto_hang_up=True`) and requires `call_id`, `auth_id`, and `auth_token` — the serializer raises a `ValueError` at construction if any are missing:

```python theme={null}
serializer = PlivoFrameSerializer(
    stream_id=stream_id,
    call_id=call_id,
    auth_id=os.getenv("PLIVO_AUTH_ID"),
    auth_token=os.getenv("PLIVO_AUTH_TOKEN"),
)
```

To leave the call up after your pipeline ends, disable it with `params=PlivoFrameSerializer.InputParams(auto_hang_up=False)`. The `keepCallAlive="true"` attribute in your Plivo XML keeps the call from being torn down when the stream ends, so the call stays up until something else ends it.

For the full parameter list, see the [`PlivoFrameSerializer` reference](/api-reference/server/services/serializers/plivo).

## Deployment

### Local Development

Use [ngrok](https://ngrok.com/) to expose your local server for testing:

```shell theme={null}
python server.py
ngrok http 8000
# Use the ngrok URL in your Plivo XML Application
```

### Pipecat Cloud Deployment

For production deployment without managing your own infrastructure, use Pipecat Cloud:

<Card title="Plivo WebSocket on Pipecat Cloud" icon="cloud" href="/pipecat-cloud/guides/telephony/plivo-websocket">
  Deploy Plivo WebSocket bots with automatic scaling and managed infrastructure
</Card>

### Self-Hosted Production Deployment

For fully self-hosted production deployment, ensure your servers are:

* Publicly accessible with HTTPS
* Able to handle concurrent WebSocket connections
* Properly configured with Plivo API credentials
* Implementing proper error handling and logging

## Next Steps

* Explore the [complete examples](https://github.com/pipecat-ai/pipecat-examples/tree/main/plivo-chatbot) for full implementations
* Learn about [Daily + Twilio SIP integration](./twilio-daily-sip) for advanced telephony scenarios
* Check out [Daily PSTN integration](./daily-pstn) for direct phone number provisioning
