By Sagar Shankaran, Founder of CallSphere
Complete setup guide for connecting Twilio to an AI voice agent — SIP trunking, webhooks, streaming, and production hardening.
Key takeaways
Twilio's quickstart will get you a phone number and a TwiML Bin that reads "hello world" in about five minutes. That is a demo, not a product. A production AI voice agent on Twilio has to answer inbound calls, open a bidirectional media stream to your LLM, survive carrier hiccups, record for compliance, and write every call into a database — all without the caller hearing a single glitch.
This guide walks through the exact wiring, from buying a number to running a bidirectional Media Streams bridge that pipes audio into the OpenAI Realtime API. Every snippet below is written to match what CallSphere runs in production for its healthcare, real estate, and sales verticals.
PSTN caller
│
▼
Twilio Number ──TwiML──► your /voice webhook
│
▼
<Start><Stream url="wss://edge.yourapp.com/twilio" />
│
▼
FastAPI edge ←──PCM16──► OpenAI Realtime API
│
▼
Postgres (call log) Queue (post-call analytics)
┌──────────────┐ TwiML ┌──────────────┐
│ Twilio Voice │──────────► │ /voice route │
└──────────────┘ └──────┬───────┘
│ │ <Stream>
▼ ▼
┌──────────────────────────────────────────┐
│ FastAPI edge (WebSocket /twilio/stream) │
│ • ulaw↔pcm16 resampler │
│ • speech-started interruption │
│ • tool dispatcher │
└─────────────┬────────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ OpenAI Realtime API │
└──────────────────────────────────────────┘
/voice webhook and a wss:// endpoint for Media Streams.In the Twilio console, buy a number with Voice capability. Set the "A call comes in" webhook to POST https://edge.yourapp.com/voice. Add a fallback URL so you degrade gracefully when your service is down.
sequenceDiagram
autonumber
participant Caller as Caller
participant Agent as CallSphere Agent
participant API as CRM API
participant DB as CRM Database
participant Webhook as Webhook Listener
Caller->>Agent: Inbound call begins
Agent->>Agent: STT plus intent detection
Agent->>API: Lookup contact by phone
API->>DB: Read contact record
DB-->>API: Contact and history
API-->>Agent: Personalized context
Agent->>API: Create call activity
Agent->>API: Update deal stage
API->>Webhook: Outbound webhook fires
Webhook-->>Agent: Confirmed
Agent->>Caller: Spoken confirmation
The /voice endpoint responds with TwiML that starts a bidirectional stream. track="inbound_track" sends caller audio only; use both_tracks if you need to record both sides.
from fastapi import FastAPI, Response, Request
app = FastAPI()
@app.post("/voice")
async def voice(req: Request):
host = req.url.hostname
twiml = f"""
<Response>
<Connect>
<Stream url="wss://{host}/twilio/stream" />
</Connect>
</Response>
""".strip()
return Response(content=twiml, media_type="application/xml")
Twilio sends G.711 ulaw frames at 8kHz over JSON messages. You convert to PCM16 at 24kHz before forwarding to OpenAI, and convert back on the return path.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
import audioop, base64, json
from fastapi import WebSocket
def ulaw_to_pcm16_24k(ulaw_bytes: bytes) -> bytes:
pcm8k = audioop.ulaw2lin(ulaw_bytes, 2)
pcm24k, _ = audioop.ratecv(pcm8k, 2, 1, 8000, 24000, None)
return pcm24k
def pcm16_24k_to_ulaw_b64(pcm24k_b64: str) -> str:
pcm24k = base64.b64decode(pcm24k_b64)
pcm8k, _ = audioop.ratecv(pcm24k, 2, 1, 24000, 8000, None)
return base64.b64encode(audioop.lin2ulaw(pcm8k, 2)).decode()
Do not rely on Twilio's call logs alone. Create your own calls table with the Twilio Call SID, your internal call ID, and a pointer to the transcript blob.
async def log_call_start(call_sid: str, from_: str, to: str):
await db.execute(
"INSERT INTO calls (call_sid, from_number, to_number, started_at) "
"VALUES ($1, $2, $3, now())",
call_sid, from_, to,
)
Add <Record> to TwiML or use the REST API to start recording mid-call. Store the recording URL in your calls table and gate playback through signed URLs.
Media Streams WebSockets must land on the same pod for the duration of the call. Use session affinity in your ingress (nginx.ingress.kubernetes.io/affinity: "cookie" or equivalent).
<Pause> timeout and max call length to prevent runaway sessions.CallSphere uses this exact Twilio wiring across every production vertical. The edge is a Python FastAPI service that bridges Twilio Media Streams to the OpenAI Realtime API with gpt-4o-realtime-preview-2025-06-03, server VAD, and PCM16 at 24kHz. Call metadata is written to per-vertical Postgres databases and a GPT-4o-mini worker handles post-call sentiment, intent, and lead scoring asynchronously.
For multi-agent verticals — 14 tools for healthcare, 10 for real estate, 4 for salon, 7 for after-hours escalation, 10 plus RAG for IT helpdesk, and an ElevenLabs sales pod with 5 GPT-4 specialists — handoffs use the OpenAI Agents SDK while the Twilio leg stays the same. The entire stack supports 57+ languages and delivers under one second end-to-end response time.
<Dial> instead of <Connect><Stream>: <Dial> bridges to another number, not a WebSocket.For most SMB use cases a Twilio phone number with Media Streams is enough. You only need SIP Trunking when you are porting existing DIDs or bridging to an on-prem PBX.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
Use ngrok to expose both your HTTP and WSS endpoints. Twilio requires TLS, so plain http tunnels do not work.
Not cleanly. Long-lived WebSockets do not fit the typical serverless lifecycle. Run the edge on a long-running container.
Use the <Dial> verb from a mid-call update REST call or hand off through the OpenAI Agents SDK to a specialist agent.
Start at 20 per 1 vCPU and measure. Event-loop contention is the bottleneck long before CPU.
Want to see a complete Twilio + Realtime deployment running live? Book a demo, read the technology page, or compare plans on the pricing page.
#CallSphere #Twilio #AIVoiceAgents #MediaStreams #FastAPI #RealtimeAPI #Production
Written by
Sagar Shankaran· Founder, CallSphere
Sagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
A how-to for Colombian education and tutoring SMBs to answer parents and students instantly, book trial classes 24/7 in Spanish and English, and grow enrollment with a CallSphere AI agent.
Tbilisi professional-services firms serving relocating founders and IT companies use CallSphere AI voice and chat agents to answer enquiries 24/7 in English, Georgian and Russian and book consultations.
A practical how-to for Palau eco-resorts and dive operators on capturing every high-value, multilingual enquiry with a CallSphere AI voice and chat agent, while honouring Palau’s marine-conservation commitments.
How salons, spas and wellness SMBs across the UAE, Saudi Arabia and Qatar use CallSphere AI voice and chat agents to capture every booking 24/7 in Arabic, English and expat languages, and cut no-shows.
How estate agents and property managers in Luxembourg City and across the Grand Duchy use CallSphere to capture multilingual viewing and enquiry calls 24/7, GDPR compliant.
A practical guide for Senegalese logistics, freight, legal and consulting SMBs in Dakar and Thiès to capture every enquiry 24/7 with a CallSphere AI voice and chat agent in French, Wolof and English.
© 2026 CallSphere LLC. All rights reserved.
Made within New York
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI