Skip to main content
Connect your agents to phone calls via Twilio. Supports both inbound (receive calls) and outbound (make calls).
Vision Agents requires a Stream account for real-time transport.

Prerequisites

  1. Twilio account with a phone number
  2. ngrok for local development (exposes your server to Twilio)
  3. Stream API credentials

Installation

uv add vision-agents[twilio]

Environment Variables

TWILIO_ACCOUNT_SID=your_account_sid
TWILIO_AUTH_TOKEN=your_auth_token
NGROK_URL=your-ngrok-subdomain.ngrok.io  # without https://
STREAM_API_KEY=your_stream_key
STREAM_API_SECRET=your_stream_secret

Inbound Calls

Twilio sends a webhook when someone calls your number. Validate the request, create a call registry entry, and return TwiML to start the media stream.
@app.post("/twilio/voice")
async def voice_webhook(
    _: None = Depends(twilio.verify_twilio_signature),
    data: twilio.CallWebhookInput = Depends(twilio.CallWebhookInput.as_form),
):
    twilio_call = call_registry.create(call_id, data, prepare=prepare_call)
    url = f"wss://{NGROK_URL}/twilio/media/{call_id}/{twilio_call.token}"
    return twilio.create_media_stream_response(url)
Configure your Twilio phone number webhook to https://your-ngrok-url/twilio/voice.

Outbound Calls

Use the Twilio REST API to initiate calls programmatically.
from twilio.rest import Client

twilio_client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
twilio_client.calls.create(
    twiml=twilio.create_media_stream_twiml(url),
    to=to_number,
    from_=from_number,
)

Key Components

ComponentDescription
TwilioCallRegistryManages pending calls and tokens
TwilioMediaStreamHandles WebSocket audio from Twilio
attach_phone_to_callConnects phone audio to Stream call
verify_twilio_signatureFastAPI dependency for webhook security
create_media_stream_responseReturns TwiML for bidirectional streaming

Next Steps