Exotel Integration
Exotel places and receives calls with bidirectional AgentStream media streaming into Dograh agents.Walkthrough video
The walkthrough covers, in order:
- ExoPhone provisioning
- Dograh telephony configuration
- Outbound call from a workflow
- Inbound call landing on a workflow
Prerequisites
- An Exotel account with AgentStream / Connect Voice AI enabled
- KYC verification completed — mandatory for all Indian accounts post-signup before ExoPhones can carry live voice traffic. Follow KYC Verification — Indian Accounts (typically < 30 minutes online).
- Account SID, API Key, and API Token (Dashboard -> Settings -> API Settings)
- A Dograh instance reachable over HTTPS and WSS
- At least one ExoPhone assigned to your account (see provisioning below — don’t assume one already exists)
Supported Exotel front-doors
Per AgentStream: what to use when, Exotel exposes five entry points to AgentStream (Connect Voice AI, Connect + Flow, ExoML outbound, Flow-Based inbound, ExoML inbound). Dograh’s Exotel provider supports exactly two of these today:- Outbound: Connect Voice AI API —
POST /v1/Accounts/{sid}/Calls/connect.jsonwithStreamUrlin the API body. No App Bazaar flow involved. - Inbound: Flow-Based via Voicebot Applet — ExoPhone → App Bazaar flow → Voicebot Applet with an HTTPS dynamic-URL pointing at Dograh.
Not currently supported
- Connect Voice AI with Flow API (outbound + App Bazaar journey). Dograh’s
initiate_callhas no path for dialing withUrl=<app_bazaar_flow_url>, andtransfer_callraisesNotImplementedError, so the Connect-applet agent-handoff pattern isn’t wired. Operators who need IVR/greeting/DTMF/agent-handoff journeys can trigger Connect + Flow calls directly against Exotel’s API from outside Dograh; the flow’s Voicebot Applet can still terminate into Dograh’s inbound dynamic-URL endpoint. - ExoML / Programmable Voice APIs (gRPC leg events + leg actions), for both outbound and inbound. Would require a gRPC endpoint on Dograh’s side and code-owned per-leg control, which is not implemented today.
ExoPhone provisioning and activation
Provision ExoPhones before configuring Dograh. All calls use HTTP Basic Auth with your API Key / API Token.- List available numbers
GET /v2_beta/Accounts/{account_sid}/AvailablePhoneNumbers/{country}/{type}{type}is one ofLandline,Mobile, orTollFree.- Optional filters:
IncomingSMS,InRegion,Contains. - Response fields include
phone_number,capabilities,country,region,rental_price. - Docs: Available numbers
- Purchase a number
POST /v2_beta/Accounts/{account_sid}/IncomingPhoneNumbers- Request body:
PhoneNumber(required);VoiceUrl,SMSUrl,FriendlyName(all optional). - Response fields include
sid,phone_number,friendly_name,capabilities,country,rental_price,currency. - Docs: Purchase number
- Verify a purchased number
GET /v2_beta/Accounts/{account_sid}/IncomingPhoneNumbers/{exophone_sid}- Returns
sid,phone_number,friendly_name,capabilities,country,region,voice_url,sms_url. - Docs: Number details
- Assign the number to a Flow
- In the Exotel dashboard, attach the ExoPhone’s Voice URL to an App Bazaar flow (see Inbound below for the Voicebot Applet wiring).
- Required before the number can carry inbound traffic, and part of the setup the reviewer’s checklist expects.
KYC (mandatory for Indian accounts): Complete KYC in the Exotel dashboard before expecting purchased numbers to become fully active for voice traffic. A purchased ExoPhone can appear in the API but silently fail on real calls until KYC clears. See KYC Verification — Indian Accounts for the three-step flow (PAN confirmation → business details → authorised signatory) and the “help me verify” escape hatch if automated checks fail.
Dograh telephony configuration
- Navigate to /telephony-configurations and click Add configuration
- Select Exotel
- Enter:
- Account SID
- API Key / API Token (HTTP Basic auth for Exotel APIs)
- API Base URL — default
https://api.in.exotel.com(India); usehttps://api.exotel.comfor other regions
- Save, then add your ExoPhone under Phone numbers in E.164 format (e.g.
+9180XXXXXXXX) - Set an Inbound workflow on that phone number in Dograh.
Programmatic configuration
When wiring Exotel via API or environment rather than the UI, the provider config accepts:Outbound
Dograh dials using Exotel Connect Voice AI (the “simplest outbound” pattern — bot is the whole experience, no App Bazaar flow):POST {api_base}/v1/Accounts/{AccountSid}/Calls/connect.json
Request fields:
From— the recipient (callee)CallerId— the ExoPhoneStreamUrl— Dograh’s tokenized WSS endpoint (fixed per call, minted byws_auth.build_media_ws_url)StreamType=bidirectionalStatusCallbackandStatusCallbackEvents[]=terminal— only attached when aworkflow_run_idis present
_exotel_dial_number() helper maps the stored E.164 CallerId to Exotel’s 0-prefixed national form (Exotel’s Connect Voice AI example uses CallerId=0XXXXXXXXXX). Example: +917314852338 → 07314852338. The destination From stays in E.164 per the same example (From=+91XXXXXXXXXX). Non-India numbers pass through unchanged.
Test from a workflow Call button. Confirm two-way audio and that hangup marks the run completed.
Per-call dynamic StreamUrl or dashboard-flow-driven outbound would require Connect + Flow or ExoML respectively — see Supported Exotel front-doors for why those aren’t implemented here.
Inbound
Dograh implements Flow-Based Inbound via the Voicebot Applet’s dynamic-URL contract. Exotel’s Stream and Voicebot Applet reference explicitly documents the applet’s URL parameter as “a WebSocket URL … or an HTTPS endpoint that dynamically returns the WSS URL” — that is the contract Dograh implements.Wiring
- In Exotel, open or create an App Bazaar flow.
- Drop a Voicebot Applet into the flow.
- Configure the applet:
- URL =
https://<dograh-host>/api/v1/telephony/inbound/run - Authentication = HTTP Basic; username = your Exotel API Key, password = your Exotel API Token (Dograh verifies this in
verify_inbound_signature). - Sample Rate =
8000. Dograh’s Exotel transport is fixed at 8 kHz today; do not append?sample-rate=…— the applet will negotiate a rate the transport doesn’t decode and audio breaks.
- URL =
- Assign the ExoPhone’s Voice URL to this flow in Exotel.
- In Dograh, assign the matching inbound workflow to the number.
Response contract
On invocation, Dograh validates auth and route mapping, creates a workflow run, and returns JSON:Voicebot Applet operational limits
Drawn from Exotel’s applet documentation:- Audio format: raw/slin — 16-bit PCM little-endian, mono, base64-encoded.
- Sample rate:
8000(PSTN). Exotel’s applet also supports16000and24000via?sample-rate=…, but Dograh’s Exotel transport is hard-coded to 8 kHz today, so leave the sample rate at the default. - Chunk size: min 3.2 KB (100 ms of audio), max 100 KB, must be a multiple of 320 bytes. Smaller chunks risk audio distortion; larger cause timeouts.
- Custom parameters: up to 3 key-value pairs appended to the URL (
?param1=value1¶m2=value2, 256 chars total).
Status callbacks
Outbound registers a per-run status callback URL:/api/v1/telephony/exotel/status-callback/{workflow_run_id}?exotel_auth=...
The exotel_auth token is an HMAC minted from your API token so Exotel’s POST does not need an Authorization header. The handler also rejects CallSid values that do not match the run’s stored call id.
Terminal events update the workflow run status.
Inbound status callbacks: the inbound dynamic-URL path currently returns the WSS URL without registering a per-run StatusCallback on the Exotel side. If you rely on Exotel-driven terminal events to close inbound runs, be aware that this is a known open item on the PR.
Phone ownership validation
Exotel does not publish a purpose-built “verify ownership” endpoint. The closest documented mechanism is Number Details — but it assumes the number is already on the account and only returns its configuration; it does not confirm ownership by itself. Dograh therefore validates ownership as a list + membership check:- Normalize the configured number and generate match-key variants (E.164, national, with/without leading
+). For Indian numbers stored as0-prefixed national forms, anINcountry hint is applied. - Query
GET /v2_beta/Accounts/{account_sid}/IncomingPhoneNumbersand iterate the returned ExoPhones. - Set-intersect the wanted variants against each entry’s
phone_number/PhoneNumber/FriendlyName(also India-normalized). - Raise
ProviderPhoneNumberLookupErrorif no variant matches, with a message pointing the operator back to the Exotel dashboard.
Troubleshooting
- Connect fails — verify Account SID, API key/token, base URL region (
api.in.exotel.comorapi.exotel.comonly), and AgentStream entitlement. - No inbound agent — confirm the ExoPhone has an inbound workflow in Dograh and the Exotel Voicebot Applet points to
/api/v1/telephony/inbound/run. - Auth failed on inbound — ensure the Voicebot Applet is configured with HTTP Basic (username = API Key, password = API Token) matching the credentials stored in Dograh.
ProviderPhoneNumberLookupErrorat config save — the ExoPhone is not on the Exotel account, the wrongapi_base_urlregion is selected, or the number was purchased but has not cleared KYC yet.- One-way audio — confirm public WSS reachability and firewall/IP rules for Exotel egress; also check the sample rate on the applet matches what your bot pipeline expects.
- Choppy or dropped audio — the outgoing chunk size may be out of range; keep chunks ≥ 3.2 KB and ≤ 100 KB, in multiples of 320 bytes. See Exotel’s WSS errors and handling.
- Status callback 401 — ensure Dograh minted the StatusCallback URL (includes
exotel_auth) and that the query string is preserved by any intervening proxy.
References
- KYC Verification — Indian Accounts (mandatory post-signup step for Indian accounts)
- ExoPhone — Available numbers
- ExoPhone — Purchase number
- ExoPhone — Number details
- AgentStream — What to use when (context for why Dograh uses these two front-doors and not ExoML)
- AgentStream — Overview & Quickstart
- AgentStream — WSS errors and handling
- Working with the Stream and Voicebot Applet
- Connect Voice AI API
- Exotel Agent-Stream reference implementation
- Exotel Agent-Stream echobot