Build Your First Voice Agent using Exotel
Overview
This guide shows you how to build a real-time voice agent that answers phone calls. It uses Exotel for telephony, Pipecat to orchestrate the real-time audio pipeline, and Sarvam AI for speech-to-text, the LLM, and text-to-speech. Itโs a great starting point for IVR replacements, customer support lines, and conversational phone agents in Indian languages.
What Youโll Build
A voice agent that can:
- Answer inbound phone calls on an Exotel number
- Listen to callers speaking, in multiple Indian languages
- Understand and process what they say
- Respond back in a natural-sounding voice, over the phone
Quick Overview
- Get an API key (Sarvam). Exotel needs no API credentials for this flow.
- Install packages:
pip install "pipecat-ai[websocket,sarvam]" python-dotenv - Create a
.envfile with your API key - Write about 80 lines of Python code
- Point an Exotel Voicebot Applet at your agentโs WebSocket URL
- Call your Exotel number
Quick Start
1. Prerequisites
- Python 3.9 or higher
- ngrok, to expose your local server during development
- An Exotel account with voice streaming enabled and a provisioned ExoPhone
- A Sarvam AI API key from your dashboard
Unlike Twilio, Exotelโs dial-in flow doesnโt require an account SID or auth token in your bot code. Pipecatโs ExotelFrameSerializer only needs the stream and call identifiers Exotel sends over the WebSocket itself.
2. Install Dependencies
macOS/Linux
Windows
3. Create Environment File
Create a file named .env in your project folder:
Replace the placeholder with your real key from the Sarvam dashboard.
4. Write Your Agent
Create agent.py:
5. Configure Exotel to Reach Your Agent
Exotel is different from Twilio here: it doesnโt fetch an XML webhook at call time. Instead, you paste your WebSocket URL directly into a Voicebot Applet inside a call flow, and Exotel opens that connection itself.
Start ngrok:
ngrok prints a forwarding URL that looks like https://xxxx.ngrok-free.app. Turn it into a wss:// URL for the next step.
The domain suffix ngrok assigns varies per account โ you may see ngrok-free.app, ngrok-free.dev, or the older ngrok.io, regardless of whether youโre on macOS, Windows, or Linux. Always use whatever URL ngrok actually prints, not the placeholder shown here.
Free ngrok URLs change every time you restart ngrok. If your agent stops receiving calls, check whether the URL in your Voicebot Applet still matches the one ngrok is currently printing.
Build the App Bazaar flow:
- In the Exotel dashboard, go to App Bazaar
- Create a new custom app (or edit an existing one)
- Add a Voicebot applet (not Stream or Passthru), and set its URL field to
wss://xxxx.ngrok-free.app/ws - Add a Hangup applet right after it, so the flow is: Call Start โ Voicebot Applet โ Hangup Applet
- Save the flow
For production use, Exotel recommends adding a Passthru applet between Voicebot and Hangup to capture session metadata (call SID, duration, recording URL) and detect disconnects. Itโs optional for getting a call working.
Assign the flow to your number:
- Go to ExoPhones, and select your number
- Under Installed App, choose the flow you just built
- Confirm the change when prompted
6. Run Your Agent
No --proxy flag is needed here since Exotel doesnโt fetch a webhook, it just connects straight to /ws.
7. Test Your Agent
Call your Exotel number from any phone. Your voice agent will pick up and start the conversation.
Customization Examples
Example 1: Hindi Voice Agent
language, voice, and target_language_code are Settings fields, not constructor keyword arguments. Passing them directly to SarvamSTTService(...) or SarvamTTSService(...) raises a TypeError on current versions of pipecat-ai. Only mode (STT) and api_key stay outside settings.
Example 2: Tamil Voice Agent
Example 3: Multilingual Agent (Auto-detect)
Use language="unknown" for support lines where callers might speak any of several languages. Sarvam auto-detects the spoken language per utterance, so the same agent can handle a Hindi caller followed by a Tamil caller without any code changes.
Example 4: Speech-to-English Agent (Saaras)
Saarika transcribes speech to text in the same language. Saaras translates speech directly to English text. Use Saaras when the caller speaks an Indian language but you want to process and respond in English.
Saaras auto-detects the source language (Hindi, Tamil, and so on) and translates spoken content directly to English text, which makes Indian-language speech usable by English-based LLMs.
Available Options
Language Codes
Speaker Voices (Bulbul v3)
Male (23): Shubh (default), Aditya, Rahul, Rohan, Amit, Dev, Ratan, Varun, Manan, Sumit, Kabir, Aayan, Ashutosh, Advait, Anand, Tarun, Sunny, Mani, Gokul, Vijay, Mohit, Rehan, Soham
Female (14): Ritu, Priya, Neha, Pooja, Simran, Kavya, Ishita, Shreya, Roopa, Tanya, Shruti, Suhani, Kavitha, Rupali
TTS Additional Parameters
You can customize the TTS service with additional parameters:
Exotel Voice Streaming defaults to 8kHz mono audio when the Voicebot Appletโs WebSocket URL doesnโt specify a rate (this guideโs URL doesnโt). Exotel also supports 16kHz and 24kHz via a ?sample-rate= query parameter on that URL, but if you use one, update audio_in_sample_rate/audio_out_sample_rate in PipelineParams to match. You donโt need to touch sample_rate on SarvamTTSService either way: Pipecat resamples the TTS output to match audio_out_sample_rate automatically.
Understanding the Call Flow
- Caller dials your Exotel number. The App Bazaar flow reaches the Voicebot Applet, and Exotel opens a WebSocket directly to your agent โ thereโs no webhook fetch in between.
- Transport Input: Your Pipecat transport receives the callerโs audio over the WebSocket, and hands it to STT.
- STT (Speech-to-Text): Converts audio to text using Sarvamโs Saarika or Saaras, and the context aggregator adds it to the conversation context.
- LLM: Generates a response using Sarvam.
- TTS (Text-to-Speech): Converts the response to audio using Sarvamโs Bulbul.
- Transport Output: Streams the audio back over the WebSocket, and Exotel plays it to the caller, while the context aggregator saves the assistantโs response to context. The Hangup Applet then ends the call once your agent closes the WebSocket.
Pro Tips
- Use
language="unknown"to automatically detect the callerโs language. This works well for multilingual support lines. - Sarvamโs models understand code-mixing, so your agent can naturally handle Hinglish, Tanglish, and other mixed languages, which is common on real support calls.
- Use
sarvam-30bfor faster responses, orsarvam-105bfor more complex conversations.
Log the transcript from context_aggregator if you want post-call analytics. Writing it to a file or database is cheap and wonโt slow down the live pipeline.
Troubleshooting
Call connects but thereโs no audio. Confirm the Voicebot Appletโs URL uses wss://, not ws:// or https://, and that it points at your current ngrok URL. Free ngrok URLs change on every restart.
Call doesnโt reach your agent at all. Double-check the flow order in App Bazaar: Call Start โ Voicebot Applet โ Hangup Applet. A missing or misordered applet is the most common cause.
API key errors. Make sure SARVAM_API_KEY is in your .env file and that the file sits in the same directory as agent.py.
Module not found. Re-run the install command for your operating system (see Step 2 above).
Poor transcription. Try language="unknown" for auto-detection, or set the exact language code (en-IN, hi-IN, and so on) if you already know it.
Choppy or robotic audio. Make sure audio_in_sample_rate and audio_out_sample_rate in PipelineParams match the rate Exotel is actually streaming: 8000 by default, or whatever you set via ?sample-rate= on the Voicebot Appletโs WebSocket URL (Exotel also supports 16000 and 24000). A mismatch causes distorted playback.
Call disconnects a few seconds after connecting. Exotel expects your WebSocket server to accept the connection within about 10 seconds. Make sure ngrok and agent.py are both already running before you place the call.
Long call cuts off unexpectedly. Exotel caps a single streaming session at around 60 minutes (this can vary by plan) โ for calls that need to run longer, design your agent to end the conversation before that limit.
Additional Resources
- Sarvam AI Documentation
- Pipecat Documentation
- Pipecat Sarvam LLM Service
- Exotel Stream and Voicebot Applet Guide
- Exotel Updated Extension Guide (timeouts, session limits, Passthru)
- Exotel Dashboard
Need Help?
- Sarvam Support: developer@sarvam.ai
- Community: Join the Discord Community
Happy Building!