# Source: https://docs.pipecat.ai/guides/telephony/daily-pstn.md

> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipecat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Daily PSTN

> Complete guide to Daily's PSTN capabilities including dial-in, dial-out, and call transfers

## Things you'll need

* An active [Daily](https://www.daily.co) developer account with API key
* At least one phone number purchased through Daily (covered below)
* For local development: ngrok to expose your bot to the Internet

<CardGroup cols={3}>
  <Card title="Dial-in Example" icon="phone-arrow-down-left" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/phone-chatbot/daily-pstn-dial-in">
    Complete dial-in implementation with the Pipecat development runner
  </Card>

  <Card title="Dial-out Example" icon="phone-arrow-up-right" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/phone-chatbot/daily-pstn-dial-out">
    Outbound calling with Daily PSTN integration
  </Card>

  <Card title="Cold Transfer Example" icon="arrow-right-arrow-left" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/phone-chatbot/daily-pstn-cold-transfer">
    Cold transfer implementation for advanced call routing
  </Card>
</CardGroup>

## Phone Number Management

Before setting up dial-in or dial-out, you'll need to purchase phone numbers through Daily.

<Card title="Daily Phone Numbers Guide" icon="phone" href="./daily-phone-numbers">
  Complete guide to searching, purchasing, and managing phone numbers with
  Daily's REST API
</Card>

## Dial-in

Dial-in allows users to call your phone number and connect directly to your Pipecat bot.

### How It Works

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

1. **Daily receives an incoming call** to your phone number
2. **Daily calls your webhook endpoint**
3. **The webhook creates a Daily room** with SIP configuration
4. **The webhook starts your bot** with the room details and caller information
5. **The caller is put on hold** with music
6. **The bot joins the Daily room** and signals readiness
7. **Daily forwards the call** to the Daily room
8. **The caller and bot are connected** for the conversation

### Local Development

The Pipecat development runner provides built-in webhook handling for Daily PSTN dial-in, eliminating the need for a separate webhook server.

#### 1. Run your bot with dial-in support

```bash  theme={null}
uv run bot.py -t daily --dialin
```

This starts a FastAPI server on port 7860 with a `/daily-dialin-webhook` endpoint.

#### 2. Expose your bot to the internet

```bash  theme={null}
ngrok http 7860
```

Copy the ngrok URL (e.g., `https://abc123.ngrok.io`).

<Tip>Use `ngrok http 7860 --subdomain your-subdomain` for a reusable URL.</Tip>

#### 3. Configure your Daily phone number

Set your phone number's `room_creation_api` webhook to:

```
https://your-ngrok-url.ngrok.io/daily-dialin-webhook
```

<Card title="Daily Dial-in Config API" icon="link" href="https://docs.daily.co/reference/rest-api/domainDialinConfig">
  Instructions for configuring the webhook URL for your phone number
</Card>

```shell Create pinless dial-in config theme={null}
curl --location 'https://api.daily.co/v1' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_DAILY_API_KEY' \
--data '{
    "properties": {
        "pinless_dialin": [
            {
                "phone_number": "DAILY_PROVISIONED_NUMBER_HERE",
                "room_creation_api": "https://your-ngrok-url.ngrok.io/daily-dialin-webhook"
            }
        ]
    }
}'
```

<Warning>
  Ensure your `DAILY_API_KEY` has the phone number associated with it. This is
  required for the `pinlessCallUpdate` API call that connects the caller to the
  room.
</Warning>

### Configure your Pipecat bot for dial-in

The bot receives dial-in information through `RunnerArguments` containing:

* `room_url`: Daily room URL for the call
* `token`: Daily room token for authentication
* `body`: Contains `DailyDialinRequest` with call details

**Bot Entry Point**:

```python bot.py theme={null}
from pipecat.runner.types import DailyDialinRequest, RunnerArguments
from pipecat.transports.daily import DailyTransport, DailyParams, DailyDialinSettings

async def bot(runner_args: RunnerArguments):
    # Parse dial-in request from runner
    request = DailyDialinRequest.model_validate(runner_args.body)

    # Configure dial-in settings with webhook data
    daily_dialin_settings = DailyDialinSettings(
        call_id=request.dialin_settings.call_id,
        call_domain=request.dialin_settings.call_domain
    )

    # Create transport with dial-in configuration
    transport = DailyTransport(
        runner_args.room_url,
        runner_args.token,
        "Voice Bot",
        DailyParams(
            api_key=request.daily_api_key,
            api_url=request.daily_api_url,
            dialin_settings=daily_dialin_settings,
            audio_in_enabled=True,
            audio_out_enabled=True,
        )
    )

    # Your bot setup and pipeline creation here...

if __name__ == "__main__":
    from pipecat.runner.run import main
    main()
```

<Card title="Complete Bot Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/blob/main/phone-chatbot/daily-pstn-dial-in/bot.py">
  See the full bot.py with argument handling, transport setup, and pipeline
  configuration
</Card>

### Customize Your Bot with Caller Information

Use the caller's phone number to personalize the conversation:

```python  theme={null}
async def bot(runner_args: RunnerArguments):
    # Parse dial-in request
    request = DailyDialinRequest.model_validate(runner_args.body)

    # Get caller's phone number
    caller_phone = request.dialin_settings.From

    # Look up customer information from your database
    customer = await get_customer_by_phone(caller_phone)

    # Customize the system prompt
    messages = [
        {
            "role": "system",
            "content": f"You are a helpful assistant for {customer.name}. "
                      f"Their account status is {customer.status}. "
                      "Keep responses concise and conversational."
        }
    ]

    # Use the customized context in your bot...
```

### Run the Example

<Card title="Complete Setup Instructions" icon="book-open" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/phone-chatbot/daily-pstn-dial-in">
  See the full README with step-by-step setup, environment variables, and
  troubleshooting tips
</Card>

## Dial-out

Dial-out allows your bot to initiate calls to phone numbers. Unlike dial-in, your bot starts the call rather than waiting for incoming calls.

<Warning>
  You must contact Daily to enable dial-out for your account. Submit a support
  request
  [here](https://docs.google.com/forms/d/1EHy2wsX20a2HjljAsJkyPqvATIM4WCvm7JzYKypGYis/edit).
</Warning>

### 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 creates a Daily room** with dial-out capabilities enabled
3. **Bot joins the Daily room** and sets up the pipeline
4. **Bot initiates the dial-out call** to the target phone number
5. **Daily connects the call** to the phone number
6. **The recipient answers** and is connected to your bot
7. **The bot handles the conversation** with the called party

### Set up your server for dial-out

The dial-out server is simpler than dial-in since you're initiating calls rather than receiving webhooks. Your server needs to:

1. **Create Daily rooms** with dial-out enabled
2. **Start bot processes** with the target phone number
3. **Handle API requests** to trigger outbound calls

<Card title="Complete Server Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/blob/main/phone-chatbot/daily-pstn-dial-out/server.py">
  See the full FastAPI server code with room creation and dial-out triggering
</Card>

### Configure your Pipecat bot for dial-out

The dial-out bot receives the target phone number and creates a transport without dial-in settings:

**Bot Entry Point**: The `bot()` method receives `RunnerArguments` containing:

* `room_url`: Daily room URL for the call
* `token`: Daily room token for authentication
* `phone_number`: Target phone number to call

**Transport Creation**: These arguments are used to configure the `DailyTransport`:

```python bot.py theme={null}
from pipecat.transports.daily import DailyTransport, DailyParams

async def bot(args: RunnerArguments):
    # Create transport for dial-out (no dial-in settings needed)
    transport = DailyTransport(
        args.room_url,
        args.token,
        "Voice Bot",
        DailyParams(
            api_url=os.getenv("DAILY_API_URL", "https://api.daily.co/v1"),
            api_key=os.getenv("DAILY_API_KEY"),
            audio_in_enabled=True,
            audio_out_enabled=True,
            video_out_enabled=False,
            transcription_enabled=True,
        )
    )

    # Start the dial-out call
    await transport.start_dialout(args.phone_number)

    # Pass transport to your bot pipeline
    # Your bot setup and pipeline creation here...
```

<Card title="Complete Bot Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/blob/main/phone-chatbot/daily-pstn-dial-out/bot.py">
  See the full bot.py with dial-out configuration and pipeline setup
</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 a dial-out 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/phone-chatbot/daily-pstn-dial-out">
  See the full README with step-by-step setup, API usage, and configuration
  details
</Card>

## Call Transfers

Daily supports cold transfers, allowing you to transfer an active call to another phone number. The bot can initiate a transfer and then leave the call, connecting the caller directly to the transfer destination.

### How Call Transfers Work

1. **Bot receives transfer request** (via function call or user input)
2. **Bot informs the caller** about the transfer
3. **Bot initiates SIP call transfer** to the destination number
4. **Daily connects the transfer** to the destination
5. **Bot leaves the call** (cold transfer)
6. **Caller and destination** continue the conversation

### Implementing Call Transfers

Call transfers are typically implemented as LLM function calls that your bot can invoke:

```python bot.py theme={null}
async def dial_operator(transport: BaseTransport, params: FunctionCallParams):
    """Function the bot can call to transfer to an operator."""
    operator_number = os.getenv("OPERATOR_NUMBER", "+1234567890")

    # Inform the user about the transfer
    content = "I'm transferring you to a supervisor now. Please hold while I connect you."
    message = {"role": "system", "content": content}
    await params.llm.push_frame(LLMMessagesAppendFrame([message], run_llm=True))

    # Execute the SIP call transfer
    transfer_params = {"toEndPoint": operator_number}
    await transport.sip_call_transfer(transfer_params)
```

### Handling Transfer Events

Your bot should handle transfer-related events to manage the call flow:

```python bot.py theme={null}
@transport.event_handler("on_dialout_answered")
async def on_dialout_answered(transport, data):
    logger.info(f"Transfer successful: {data}")
    # Cold transfer: bot leaves, caller and operator continue
    await task.queue_frames([EndFrame()])
```

<Card title="Complete Transfer Implementation" icon="code" href="https://github.com/pipecat-ai/pipecat-examples/tree/main/phone-chatbot/daily-pstn-cold-transfer">
  See the full call transfer example with LLM function calls, event handling,
  and error management
</Card>

## Deployment

### Pipecat Cloud

For production deployment without managing your own infrastructure, use Pipecat Cloud. Pipecat Cloud handles all webhook infrastructure, room creation, and bot scaling automatically.

<CardGroup cols={2}>
  <Card title="Daily Dial-in on Pipecat Cloud" icon="phone-arrow-down-left" href="/deployment/pipecat-cloud/guides/telephony/daily-dial-in">
    Complete guide for deploying dial-in bots with automatic webhook handling
  </Card>

  <Card title="Daily Dial-out on Pipecat Cloud" icon="phone-arrow-up-right" href="/deployment/pipecat-cloud/guides/telephony/daily-dial-out">
    Complete guide for deploying dial-out bots with caller ID management
  </Card>
</CardGroup>

### Self-Hosted Deployment

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

* Publicly accessible with HTTPS
* Able to handle concurrent requests
* Properly configured with your Daily API credentials

## Next Steps

* Explore the [complete examples](https://github.com/pipecat-ai/pipecat/tree/main/examples) for full implementations
* Learn about [Daily's SIP integration](./twilio-daily-sip) for more advanced telephony scenarios
* Check out [Daily's REST API documentation](https://docs.daily.co/reference) for additional configuration options