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

# Twilio Phone Agent

> Step-by-step guide to inbound and outbound phone calls with Twilio Media Streams

<Card title="View Example on GitHub" icon="github" href="https://github.com/GetStream/Vision-Agents/tree/main/examples/03_phone_and_rag_example">
  Both `outbound_phone_example.py` and `inbound_phone_and_rag_example.py` live in this folder
</Card>

Build inbound and outbound phone agents with [Twilio](https://www.twilio.com/) Media Streams, [Stream](https://getstream.io/) edge transport, and Gemini. This tutorial covers phone plumbing only — no RAG. For knowledge retrieval on calls, continue to [Phone Support Agent (RAG)](/examples/phone-and-rag).

<Info>
  Vision Agents uses [Stream Video](https://getstream.io/video/) for real-time WebRTC transport by default. [External WebRTC transports](/integrations/introduction-to-integrations#edge-transport) are supported as well. Most AI providers offer free tiers to get started.
</Info>

## What You Will Build

* Make an outbound call programmatically (e.g. call your cell to test audio)
* Answer inbound calls on your Twilio number with a voice AI agent
* Handle bidirectional audio via Twilio Media Streams over WebSocket
* Bridge phone audio into a Stream call with `attach_phone_to_call`

<Warning>
  For optimal latency, deploy in **US-east**. Local development adds round-trip
  latency through ngrok and your machine.
</Warning>

## Prerequisites

Create a `.env` file at the [Vision Agents](https://github.com/GetStream/Vision-Agents) repo root:

```bash theme={null}
STREAM_API_KEY=
STREAM_API_SECRET=
GOOGLE_API_KEY=
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
```

You also need [ngrok](https://ngrok.com/) and a Twilio phone number. See the [Twilio integration](/integrations/telephony/twilio) for webhook and API details.

## Run the example

<Steps>
  <Step title="Clone and install" icon="folder-plus">
    Clone the repo and install dependencies from the root:

    ```bash theme={null}
    git clone git@github.com:GetStream/Vision-Agents.git
    cd Vision-Agents
    uv sync
    ```
  </Step>

  <Step title="Start ngrok" icon="globe">
    Expose port 8000 so Twilio can reach your local server:

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

    Copy the HTTPS hostname (without `https://`) — you'll use it as `NGROK_URL`.
  </Step>

  <Step title="Configure your Twilio number" icon="phone">
    In the [Twilio Console](https://console.twilio.com/):

    1. Go to **Phone Numbers → Manage → Active numbers**
    2. Select your number (or buy one)
    3. Under **Voice Configuration**, set **A call comes in** to **Webhook**
    4. Enter `https://<NGROK_URL>/twilio/voice` with method **HTTP POST**

    See [Twilio integration](/integrations/telephony/twilio) for how the webhook handler works.
  </Step>

  <Step title="Make an outbound call" icon="phone-arrow-up-right">
    In a new terminal, from the example directory:

    ```bash theme={null}
    cd examples/03_phone_and_rag_example
    NGROK_URL=your-subdomain.ngrok-free.app uv run outbound_phone_example.py \
      --from +15551234567 \
      --to +15557654321
    ```

    Replace with your Twilio number (`--from`) and a destination you can answer (`--to`, often your cell). This starts the HTTP server and initiates the outbound call.
  </Step>

  <Step title="Run the inbound agent" icon="phone-arrow-down-left">
    With ngrok and your Twilio webhook still configured, start the inbound server:

    ```bash theme={null}
    cd examples/03_phone_and_rag_example
    NGROK_URL=your-subdomain.ngrok-free.app uv run inbound_phone_and_rag_example.py
    ```

    RAG is optional at this stage — the agent runs with Gemini even without extra RAG configuration.
  </Step>

  <Step title="Call your number" icon="microphone">
    Dial your Twilio number from any phone. You should hear the AI agent answer and respond in real time.
  </Step>
</Steps>

## How it works

Twilio uses [TwiML](https://www.twilio.com/docs/voice/twiml) to control calls. The voice webhook returns a `<Connect><Stream>` response that pipes audio to your WebSocket:

1. **`POST /twilio/voice`** — validates the Twilio signature, registers the call in `TwilioCallRegistry`, returns TwiML with a media stream URL
2. **`WS /twilio/media/{call_id}/{token}`** — accepts the WebSocket, runs `TwilioMediaStream`, validates the token
3. **`attach_phone_to_call`** — bridges Twilio mulaw audio ↔ the Stream call where your agent runs

The inbound script uses `ProxyHeadersMiddleware` so signature validation works when ngrok terminates HTTPS.

## Next Steps

<CardGroup cols={2}>
  <Card title="Phone Support Agent (RAG)" icon="book" href="/examples/phone-and-rag">
    Add Gemini FileSearch or TurboPuffer knowledge retrieval
  </Card>

  <Card title="Twilio Integration" icon="plug" href="/integrations/telephony/twilio">
    Plugin API reference and components
  </Card>

  <Card title="Phone Calling" icon="route" href="/guides/calling">
    Provider overview and learning path
  </Card>

  <Card title="Telnyx" icon="phone" href="/integrations/telephony/telnyx">
    Alternative telephony provider
  </Card>
</CardGroup>
