Guides

Exotel

Connect Exotel numbers to the voice engine for inbound and outbound calls, and what has and has not been proven live.

Exotel calls reach the own voice engine through Exotel's Voicebot applet, which streams the call's audio over a WebSocket.

Warning: The Exotel integration was built and tested against a simulated Exotel. The engine's own notes record a single real Exotel call. An outbound call placed through Exotel's API, the status callback, and a transfer through an Exotel flow have not been run on a real account. Treat the first live calls as a verification step.

What you need

  • An Exotel account with an ExoPhone, and Voicebot (bidirectional streaming) enabled. Ask Exotel support if the Voicebot applet is missing from your App Bazaar.
  • An operator who runs the platform in live telephony mode with the own engine reachable at a public wss:// address.
  • Your Exotel API key, API token, account SID, and the id of the flow you build below.

How audio flows

Exotel opens a WebSocket to the engine and sends JSON events: connected, start, media, dtmf, stop. Audio is base64 16-bit PCM, 8 kHz mono, both ways. Closing the socket is how the engine hangs up: Exotel has no hang-up API for these calls.

Protocol detail is in Engine protocol.

Step 1: build one flow in Exotel

Create an app (flow) in App Bazaar with these applets, once:

  1. Voicebot. URL: wss://<user>:<password>@<public engine host>/exotel?sample-rate=8000. The user and password are the ones the operator set on the engine. Leave custom parameters empty.
  2. Passthru after it, pointing at https://<public API host>/engine/exotel/after-stream. The platform answers 200 with a phone number as plain text when the agent transferred the call, and 404 otherwise.
  3. On Passthru's 200 branch, a Connect applet to your human queue or number. On the other branch, Hangup.

Note the flow's app id. Without the Passthru step, an ordinary hang-up from the engine would fall through to whatever applet comes next.

Step 2: add your credentials

Store them as provider keys, one request per key. Values are encrypted at rest.

bash
curl -X POST https://api.sevennadi.si/providers \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"provider_name": "EXOTEL_API_KEY", "provider_value": "<your key>"}'
json
{"message": "successful", "status": "added"}
provider_nameValue
EXOTEL_API_KEYAPI key
EXOTEL_API_TOKENAPI token
EXOTEL_ACCOUNT_SIDAccount SID
EXOTEL_APP_IDThe flow's app id from step 1
EXOTEL_SUBDOMAINOptional. api.in.exotel.com for the India cluster; default api.exotel.com

The operator can instead set the same values for the whole platform. Your own keys take precedence.

Step 3: register the number and the agent

Register the ExoPhone, then point the agent at Exotel and the own engine.

bash
curl -X POST https://api.sevennadi.si/phone-numbers/import \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"phone_number": "+918012345678", "telephony_provider": "exotel"}'

curl -X PATCH https://api.sevennadi.si/v2/agent/3c90c3cc-0d44-4b50-8822-8dd25736052a \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"agent_config": {"telephony_provider": "exotel"}}'

telephony_provider sets the agent's input and output provider to exotel and the audio format to pcm. In the dashboard this is the Telephony Provider setting in Agent Studio.

The agent must also run on the own engine. Put "engine": "own" in agent_config when you create or replace the agent, or send "agent_data": {"engine": "own"} with each call. If the operator's default engine is already own, nothing is needed.

Outbound calls

Place calls as usual with POST /call, a batch or a campaign, using the ExoPhone as from_phone_number.

  1. The platform asks Exotel to connect the recipient to your flow, with your ExoPhone as caller ID and a custom field carrying the execution id and a one-call token.
  2. When the recipient answers, the flow's Voicebot applet connects to the engine. Exotel passes the custom field on, and the engine uses it to fetch the call's session.
  3. The engine runs the conversation and reports the transcript and usage.
  4. Exotel posts the final status, duration and recording to the platform.

A wrong token closes the stream. With no credentials, the execution ends error with:

text
No Exotel credentials: add EXOTEL_API_KEY, EXOTEL_API_TOKEN, EXOTEL_ACCOUNT_SID, EXOTEL_APP_ID via POST /providers

Inbound calls

Assign the same flow to the ExoPhone in Exotel, then link the agent:

bash
curl -X POST https://api.sevennadi.si/inbound/setup \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "3c90c3cc-0d44-4b50-8822-8dd25736052a", "phone_number_id": "9a8b7c6d5e4f40312a1b0c9d8e7f6a5b"}'

When someone dials the number, the engine checks the applet's password, the source address and the dialled number, then asks the platform which agent answers. Numbers are matched on their last ten digits, because Exotel sends local formats. If no agent is linked the engine hangs up. Inbound flows send no status callback, so the call is marked completed when the engine reports its result.

Transfer to a person

Give the agent a transfer_call tool (see Function tools). When it fires, the engine says the handover line, reports the transfer and closes the stream. Exotel then runs the Passthru applet, receives the number with 200, and the Connect applet dials it. The execution carries transfer_call_data.

What the operator must configure

  • Live telephony mode, and the public https address of the API.
  • The engine's public wss:// address, its Exotel WebSocket user and password, and a shared secret between engine and platform.
  • The engine's allow-lists: Exotel source addresses and, optionally, the dialled numbers it accepts.

See Deployment and Engine security.

Limitations

  • Not yet verified on a live account: how Exotel delivers the custom field to the stream (the engine reads every documented location), the exact fields of the status callback, whether the Connect applet accepts the number returned by the Passthru URL, and whether Exotel accepts an E.164 caller ID for your ExoPhone.
  • Only the own engine can take Exotel calls.
  • A call beyond the engine's capacity is refused before it is answered, with no spoken message. Put a busy announcement in your Exotel flow.