Skip to content

Telephony Providers

The platform supports three telephony providers through a common abstraction layer. Each provider implements the same interface: transport creation, webhook response building, and outbound call initiation.

Provider Comparison

FeatureTwilioExotelVobiz
Audio encodingmu-law 8 kHzPCM 8 kHzmu-law 8 kHz
SerializerTwilioFrameSerializerExotelFrameSerializerVobizFrameSerializer
Inbound webhook formatTwiMLExoMLVobiz XML
Outbound APIcalls.create()/Calls/connect.jsonREST API
Auto hang-upYes (via REST)NoYes (via serializer)
DTMF supportYesYesYes
Default concurrency101010

Switching Providers

Set the default provider in .env:

env
TELEPHONY_PROVIDER=twilio   # or exotel, or vobiz

Or configure via the settings API:

bash
curl -X PUT http://localhost:8000/api/settings/telephony \
  -H "Content-Type: application/json" \
  -d '{ "provider": "exotel" }'

Individual outbound calls can override the provider per-call:

json
{ "provider": "exotel" }

Twilio

Required Settings

VariableDescription
TWILIO_ACCOUNT_SIDAccount SID from Twilio console
TWILIO_AUTH_TOKENAuth token from Twilio console
PUBLIC_BASE_URLPublic HTTPS URL for webhooks

Optional:

VariableDescription
TWILIO_PHONE_NUMBERDefault caller ID for outbound calls

Inbound Setup

Configure your Twilio phone number's Voice webhook:

POST https://your-domain.com/telephony/twilio/inbound/{agent_name}

The app returns TwiML that connects Twilio to the WebSocket:

xml
<Response>
  <Connect>
    <Stream url="wss://your-domain.com/ws/twilio/{agent_name}">
      <Parameter name="agent_name" value="sales-agent" />
      <Parameter name="direction" value="inbound" />
      <Parameter name="from_number" value="+1..." />
      <Parameter name="to_number" value="+1..." />
      <Parameter name="twilio_call_sid" value="CA..." />
    </Stream>
  </Connect>
</Response>

Outbound Flow

  1. POST /api/calls/outbound creates a call record
  2. Twilio REST API calls.create() is called with inline TwiML
  3. TwiML connects the answered call to wss://.../ws/twilio/{agent_name}
  4. WebSocket handler starts the voice pipeline

Testing Checklist

  • Backend running and accessible
  • Public tunnel active (ngrok/cloudflared for local dev)
  • PUBLIC_BASE_URL matches the tunnel URL
  • Twilio webhook pointed at /telephony/twilio/inbound/{agent_name}
  • Agent exists in the database
  • STT/LLM/TTS API keys configured

Exotel

Required Settings

VariableDescription
EXOTEL_ACCOUNT_SIDAccount SID from Exotel dashboard
EXOTEL_API_KEYAPI key
EXOTEL_API_TOKENAPI token
PUBLIC_BASE_URLPublic HTTPS URL for webhooks

Optional:

VariableDescription
EXOTEL_PHONE_NUMBERDefault virtual number
EXOTEL_API_BASEAPI base URL (defaults to Exotel's standard endpoint)

Inbound Setup

  1. Log in to Exotel App Bazaar
  2. Create a Voicebot applet
  3. Set the webhook URL to:
    POST https://your-domain.com/telephony/exotel/inbound/{agent_name}
  4. Assign the applet to your virtual number's inbound flow

When a call arrives:

  1. Exotel hits the inbound webhook → receives ExoML with <Connect><Stream>
  2. Exotel opens a WebSocket to /ws/exotel/{agent_name} and streams PCM audio

Outbound Flow

  1. POST /api/calls/outbound with "provider": "exotel"
  2. Server calls Exotel REST API (/Calls/connect.json)
  3. A StatusCallback URL is passed that returns ExoML when the call is answered
  4. ExoML contains <Connect><Stream> → audio flows into the pipeline

Call Flow

Caller / Callee

   Exotel
      ↕  (WebSocket — linear PCM 8 kHz)
  /ws/exotel/{agent}

ExotelFrameSerializer  ← resamples to pipeline rate

Voice Pipeline (STT → LLM → TTS)

ExotelFrameSerializer  ← resamples back to 8 kHz

   Exotel → Caller

Vobiz

Required Settings

VariableDescription
VOBIZ_AUTH_IDAuth ID from Vobiz
VOBIZ_AUTH_TOKENAuth token from Vobiz
PUBLIC_BASE_URLPublic HTTPS URL for webhooks

Optional:

VariableDescription
VOBIZ_PHONE_NUMBERDefault phone number

Inbound Setup

Configure your Vobiz number's inbound webhook:

POST https://your-domain.com/telephony/vobiz/inbound/{agent_name}

The app returns Vobiz XML that connects to the WebSocket for audio streaming.

Outbound Flow

  1. POST /api/calls/outbound with "provider": "vobiz"
  2. Server calls Vobiz REST API
  3. An answer_url callback is passed that returns XML when the call is answered
  4. XML connects the WebSocket → pipeline runs

Notes

  • Vobiz uses a Plivo-compatible protocol
  • The VobizFrameSerializer handles mu-law 8kHz encoding and supports auto hang-up
  • WebSocket parsing extracts metadata from query parameters (not from the WebSocket start message)

Concurrency Limits

Each provider has a configurable maximum concurrent call limit (default: 10).

  • Enforced at WebSocket accept — returns 503 if the limit is reached
  • Enforced at POST /api/calls/outbound — returns an error if the limit is reached
  • Configurable per-provider in telephony settings

Public URL Requirements

All providers require a publicly accessible HTTPS URL for webhooks and WebSocket connections. For local development, use a tunnel:

bash
# ngrok
ngrok http 8000

# cloudflared
cloudflared tunnel --url http://localhost:8000

Set the resulting URL:

env
PUBLIC_BASE_URL=https://your-tunnel-url.com

This URL is used to build:

  • https://.../telephony/{provider}/inbound/{agent} (webhook)
  • wss://.../ws/{provider}/{agent} (WebSocket)