Programmable Voice APIs with AgentStream
When you build bot-driven voice experiences, reducing perceived latency is critical. With Exotel ExoML, you can control call legs and media actions in real time. This guide explains two recommended approaches:
- Approach 1: Create a customer leg and immediately start a stream.
- Approach 2: Create a leg, start a stream, and optionally play a short greeting (say/play) in parallel while the bot connects.
Both flows are supported with existing ExoML — IntroductionExotel ExoML.
Prerequisites
- An Exotel account and valid account_sid, key and Token
- An exophone configured for outbound calls
- A gRPC endpoint to receive leg events.
- A WebSocket bot server that supports Exotel streaming and events
Approach 1: Create Leg + Start Stream (Bot-First)
Base URL
All ExoML Aare served from the Exotel CPaaS API host.
Base URL format
This is the simplest flow: connect the customer leg, then hand it directly to your bot.
Step 1. Create the leg
POST /v2/accounts/{account_sid}/legs
Content-Type: application/json
{
"contact_uri": "074xxxxx773",
"exophone": "0204xxxxx38",
"leg_event_endpoint": "grpc://<your-example-endpoint>",
"timeout": 30
}You will receive events such as leg_connecting, leg_ringing, and finally leg_answered.
Step 2. Start the stream
On leg_answered, start the stream:
POST /v2/accounts/{account_sid}/legs/{leg_sid}/actions/start_stream
Content-Type: application/json
{
"direction": "bidirectional",
"url": "wss://bot.example.com/stream",
"content_type": "audio/x-mulaw;rate=8000"
}At this point, audio flows between the customer and your bot.
Approach 2: Create Leg + Start Stream + Say/Play (Parallel)
In many customer-facing scenarios, even a 1–2s delay feels like silence. To improve perception, you can play a short greeting while the stream session is warming up.
Step 1. Create the leg
Same as Approach 1.
Step 2. Start actions in parallel
On leg_answered, issue two actions:
Start stream
POST /v2/accounts/{account_sid}/legs/{leg_sid}/actions/start_stream
{
"direction": "bidirectional",
"url": "wss://bot.example.com/stream",
"content_type": "audio/x-mulaw;rate=8000"
}
Start greeting (choose one):
- Say
POST /v2/accounts/{account_sid}/legs/{leg_sid}/actions/start_say
{
"text": "Hello",
"loop": 0
}- Play
POST /v2/accounts/{account_sid}/legs/{leg_sid}/actions/start_play
{
"url": "https://example.com/contact-center-tone.wav",
"loop": 0
}Step 3. Stop greeting when the stream is ready
As soon as you receive the stream_started event, stop the placeholder:
POST /v2/accounts/{account_sid}/legs/{leg_sid}/actions/stop_say
or
POST /v2/accounts/{account_sid}/legs/{leg_sid}/actions/stop_play
This ensures the bot audio seamlessly takes over without overlap.
When to Use Each Approach
Scenario | Recommended Flow |
|---|---|
Bot-first, IVR-style journeys | Approach 1 |
Sales / Collections (instant feel) | Approach 2 |
Contact center simulation | Approach 2 |
Tech support bot only | Approach 1 |
Key Notes
- Parallelism: Exotel supports issuing start_stream and start_say/start_play together on the same event.
- Greeting length: Keep placeholder audio short (200–500 ms) so the bot can take over naturally.
- Stop timing: Always stop say/play when you receive stream_started.
Next Steps
- Get ExoML enabled for your account
- Explore StopSay/StopPlay timing to fine-tune transitions.