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
LinkedInSagar 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 practical guide for medical clinics and aged-care providers in Sydney, Melbourne, Auckland, and Wellington to triage after-hours calls with AI voice agents under the Privacy Act.
A 2026 look at Austrian SMBs and the tourism-driven hospitality sector in Vienna, Graz and the alpine regions. How CallSphere AI voice and chat agents handle multilingual bookings 24/7, DSGVO-compliant, in German, English and more.
Azerbaijani law firms, accountants, and real estate agencies lose clients to unanswered calls. CallSphere books consultations 24/7 in Azerbaijani, Russian, and English across Baku and Ganja.
A practical guide for automotive businesses across the Balkans to deploy a CallSphere AI voice and chat agent that books service, answers parts questions, and captures every lead in every local language.
San Pedro on Ambergris Caye runs on divers and property buyers who inquire from every time zone. See how CallSphere AI voice + chat agents answer reef-trip bookings and real estate leads 24/7 in English and Spanish.
A pain-to-solution guide for logistics operators and professional-services firms across Poland, Czechia, Hungary and Slovakia to capture cross-border calls 24/7 with a CallSphere AI agent.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI