---
title: Connect Voice AI API
slug: exotel-agentstream/connect-voice-ai-api
createdAt: 2026-04-08T14:46:17.109Z
---

The Connect voice to Bot API lets you programmatically call a phone number and connect the call to a conversational AI bot in real time. Audio flows in both directions — the caller speaks to the bot, and the bot responds to the caller — over a secure WebSocket connection.

**Typical use cases:** AI-powered outbound campaigns, virtual customer care agents, automated surveys, and appointment reminders with live confirmation.

## Before You Start

You will need:

- Your Exotel Account SID, API Key, and API Token (available from your Exotel Dashboard).
- An ExoPhone (virtual number) to use as the Caller ID.
- A WebSocket server endpoint (your bot service) that accepts audio in real time.

## How It Works

1. You send an API request with the caller's phone number and your bot's WebSocket URL.
2. Exotel dials the phone number.
3. Once the call is answered, Exotel opens a connection to your WebSocket server.
4. Audio is streamed live between the caller and your bot for the duration of the call.
5. When the call ends (by either party), Exotel sends a status update to your callback URL.

## API Reference

**Endpoint:**

:::BlockQuote
POST /v1/Accounts/&#x7B;AccountSid}/Calls/connect
:::

**Base URLs:**

| Region    | Base URL                   |
| --------- | -------------------------- |
| Singapore | https\://api.exotel.com    |
| Mumbai    | https\://api.in.exotel.com |

Authentication uses HTTP Basic Auth with your API Key as the username and API Token as the password.

### Parameters

Required

| Parameter  | Description                                                                                                                                          |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| From       | The phone number to call. Use international format (e.g., +919876543210).                                                                            |
| CallerId   | Your Exotel virtual number that appears as the caller ID.                                                                                            |
| StreamUrl  | The WebSocket URL of your bot server. Must start with ws\:// or wss\://.<br />max length **600** (STREAM\_URL\_MAX\_LENGTH), including query string. |
| StreamType | Set this to **bidirectional** to enable two-way audio.                                                                                               |

Optional

| Parameter            | Description                                                                                                                                                                                                                                                                                                                                                                                         |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Record               | Set to true to record the call. Default: false.                                                                                                                                                                                                                                                                                                                                                     |
| RecordingChannels    | single (merged) or dual (separate track per side). Default: single.                                                                                                                                                                                                                                                                                                                                 |
| TimeLimit            | Maximum call duration in seconds. Up to 14,400 (4 hours).                                                                                                                                                                                                                                                                                                                                           |
| CustomField          | CustomField \| Opaque string on the call (max 128 characters). Returned on event StatusCallbacks when you use StatusCallbackEvents. Not sent to the bot as start.custom\_parameters — put bot keys on the StreamUrl query string.                                                                                                                                                                   |
| StatusCallback       | A POST HTTPS URL on your server that Exotel will call with updates when the call status changes.                                                                                                                                                                                                                                                                                                    |
| StatusCallbackEvents | StatusCallbackEvents \| answered, terminal, and/or ringing. Send as StatusCallbackEvents\[]=terminal. Needed for CustomField / DisconnectedBy on the webhook. Without it, StatusCallback is a thin payload (no CustomField). See :inlineImage[]{src="https://www.google.com/s2/favicons?domain=exotel.com&sz=64" alt caption width="32" height="32"}[StatusCallback](docId\:IYhq4ZnAjjJYFNxYwZ4ue). |
| StreamName           | An optional label for the stream, up to 32 characters.                                                                                                                                                                                                                                                                                                                                              |

### Example Request

bash

```curl
curl -u '<api_key>:<api_token>' -X POST \
  'https://api.in.exotel.com/v1/Accounts/<AccountSid>/Calls/connect' \
  -F 'From=+91XXXXXXXXXX' \
  -F 'CallerId=0XXXXXXXXXX' \
  -F 'StreamUrl=wss://your-bot.example.com/media?campaign_id=C123' \
  -F 'StreamType=bidirectional' \
  -F 'CustomField={"campaign_id":"C123"}' \
  -F 'Record=true' \
  -F 'StatusCallback=https://your-server.com/callback' \
  -F 'StatusCallbackEvents[]=terminal' \
  -F 'StatusCallbackContentType=application/json'
```

### Response

A successful request returns a Call object immediately. The call is still being set up at this point — use StatusCallback to track when the call is answered and when it ends.

json

:::BlockQuote
\{  "Call": \{    "Sid": "a1b2c3d4e5f6...",    "Status": "in-progress",    "From": "+91XXXXXXXXXX",    "PhoneNumberSid": "0XXXXXXXXXX",    "Direction": "outbound-api",    "DateCreated": "2025-06-01 10:00:00",    "RecordingUrl": null  }}
:::

| Field        | What it means                                                               |
| ------------ | --------------------------------------------------------------------------- |
| Sid          | A unique ID for this call. Save it to look up call details later.           |
| Status       | Current state of the call.                                                  |
| From         | The number that was dialed.                                                 |
| RecordingUrl | Link to the recording once the call is complete (if recording was enabled). |

**Call status values:**

| Status      | Meaning                    |
| ----------- | -------------------------- |
| queued      | Call is being prepared.    |
| in-progress | Call is active.            |
| completed   | Call ended normally.       |
| failed      | Call could not be placed.  |
| busy        | The number was busy.       |
| no-answer   | The number did not answer. |

## Configuring Your Bot's WebSocket Server

Your bot must accept a WebSocket connection and handle audio in real time. Key points:

- Exotel sends audio as raw PCM or mulaw at 8 kHz by default. To request a different sample rate, append it to your StreamUrl: wss\://your-bot.example.com/media?sample-rate=16000. Supported values: 8000, 16000, 24000.
- Your bot can send audio back to the caller at any time during the call.
- When your bot wants to end the call, it closes the WebSocket connection.

For full protocol details, see the AgentStream documentation.

## Things to Keep in Mind

- StreamUrl must use ws\:// or wss\://. Plain HTTP URLs are not supported.
- The full StreamUrl (including any query string) must be under 600 characters.
- If you provide a StreamName, it must be 32 characters or fewer.
- Query parameters on StreamUrl are how you pass custom data into the bot (start.custom\_parameters). Prefer this over StreamCustomField.
- https\:// is not valid as StreamUrl. Resolve any HTTPS discovery URL yourself, then pass wss\://… (with your query params on that WSS URL).
- StatusCallbackEvents work on Connect Voice AI. They are not accepted with a flow Url (…/exoml/start\_voice/&#x7B;app\_id}) — API returns 400.
- Webhook fields (CustomField, DisconnectedBy, outcomes): [StatusCallback](docId\:IYhq4ZnAjjJYFNxYwZ4ue).
- This feature must be enabled on your account before use. Contact hello\@exotel.com to get started.

## Need Help?

- Read the AgentStream guide to understand how Exotel streams audio to your bot.
- For API errors and response codes, see the Error Code Reference.
- Contact support at hello\@exotel.com.
