Programmable Voice APIs with AgentStream
Full runtime control via Legs API — per-call stream URLs, dynamic routing, and greeting + stream in parallel.
Works for outbound (POST /legs) and inbound (Exophone attached to a gRPC endpoint). See What to use when.
Authentication
HTTP Basic Auth — API Key as username, API Token as password.
Content-Type: application/json
Base URL: https://cpaas-api.in.exotel.com/v2/accounts/{account_sid}
(Singapore: cpaas-api.exotel.com)
Create leg (dial)
Request parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
contact_uri | Yes | String | Number to dial (E.164) |
exophone | Yes | String | Your ExoPhone |
leg_event_endpoint | Yes | String | gRPC endpoint for leg events |
timeout | No | Integer | Ring timeout in seconds |
Example request
curl -u '<api_key>:<api_token>' -X POST \
'https://cpaas-api.in.exotel.com/v2/accounts/<account_sid>/legs' \
-H 'Content-Type: application/json' \
-d '{
"contact_uri": "+919876543210",
"exophone": "08047491899",
"leg_event_endpoint": "grpc://your-event-server.example.com",
"timeout": 30
}'
Try It
Exotel emits: leg_connecting → leg_ringing → leg_answered
Start stream
Call on leg_answered.
Request parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
direction | Yes | String | bidirectional for Voice AI |
url | Yes | String | Bot WebSocket URL (wss://) |
content_type | No | String | e.g. audio/x-mulaw;rate=8000 |
Example request
curl -u '<api_key>:<api_token>' -X POST \
'https://cpaas-api.in.exotel.com/v2/accounts/<account_sid>/legs/<leg_sid>/actions/start_stream' \
-H 'Content-Type: application/json' \
-d '{
"direction": "bidirectional",
"url": "wss://bot.example.com/stream",
"content_type": "audio/x-mulaw;rate=8000"
}'
Try It
Optional — greeting while stream initialises
Fire with start_stream on leg_answered to avoid dead air.
Start say
curl -u '<api_key>:<api_token>' -X POST \
'https://cpaas-api.in.exotel.com/v2/accounts/<account_sid>/legs/<leg_sid>/actions/start_say' \
-H 'Content-Type: application/json' \
-d '{ "text": "Please hold.", "loop": 0 }'
Try It
Stop say
Call on stream_started:
curl -u '<api_key>:<api_token>' -X POST \
'https://cpaas-api.in.exotel.com/v2/accounts/<account_sid>/legs/<leg_sid>/actions/stop_say'
Try It
| Scenario | Use greeting? |
|---|---|
| Inbound IVR / tech support | Usually no |
| Outbound sales / collections | Yes |
Inbound ExoML
- Implement a gRPC leg-event endpoint
- Attach the Exophone to that endpoint (not to an App Bazaar flow)
- On inbound
leg_answered, issuestart_stream(and optional say/play)
No Voicebot applet required — your service is the flow.