# Exotel vSIP

Source: https://docs.usetone.ai/sip-trunking/exotel-vsip

> Point an Exotel SIP trunk at Tone — PoPs, transports, the X-Exotel headers, and the Exophone rule that rejects outbound calls.

*Exotel's SIP trunking product (vSIP) connects a SIP stack straight to their voice network,
instead of the WebSocket streaming their Voicebot applet uses. This page configures it against
Tone.*

**Exotel classes vSIP as Alpha and puts no SLA behind it.** There is no self-serve API: trunks
are provisioned by hand by your account manager, and SIP traffic is blocked until your account is
KYC-verified and upgraded to a full account. Budget for a few days of email.

## Before you start

- A full, KYC-verified Exotel account (`my.in.exotel.com` or `my.exotel.com`).
- At least one **Exophone** — the number your calls will present. Procured through
  hello@exotel.com.
- A Tone organization with KYC verified and **SIP trunking** enabled by Tone support.

## Which PoP

Exotel terminates on regional edge PoPs. Pick the one your account is on — ask your account
manager if you are not sure, because it is set per account, not per trunk.

| Region | SIP proxy | Media IPs |
|---|---|---|
| Mumbai | `pstn.in2.exotel.com` | `182.76.143.61`, `122.15.8.184` |
| Mumbai Cloud | `pstn.in4.exotel.com` | — |
| Karnataka | `pstn.in1.exotel.com` | `14.194.10.247`, `61.246.82.75` |
| Singapore | `pstn.sgp1.exotel.com` | `18.142.150.245`, `122.248.223.73` |

🔴 **A Singapore PoP sends your call audio out of India.** Tone keeps media in Mumbai
(`ap-south-1`), but the leg between Exotel and the PSTN is Exotel's, and on `sgp1` it is not in
country. If your compliance position depends on media staying in India, ask Exotel to move the
account to `in2` or `in4` before you build on it.

## Transports

| Transport | Port | Encryption |
|---|---|---|
| TLS | **443** | SIP over TLS + SRTP (`a=crypto`) — recommended |
| TCP | **5070** | none |

**SIP over UDP is not supported, and neither is `REGISTER` authentication.** Exotel authenticates
you by source IP (or by FQDN), which lines up with Tone's `ip_acl` inbound mode.

Media is UDP `10000–40000`, though Exotel asks you to narrow to `10000–20000` — two ports per
call, and their media servers cap at 3000 concurrent. Codecs are **PCMA (G.711 A-law) preferred**,
PCMU as fallback; DTMF is RFC 2833. Rate limit is **200 calls per minute per trunk**.

## What to send Exotel

Email your account manager with all of it at once — each round trip costs a day:

- your **Account SID**
- the **Exophones** to route
- **Inbound to Tone** (Exotel → Tone): Tone's signalling IPs, shown on your trunk's page in the
  dashboard. Transport `TLS/443` or `TCP/5070`.
- **Outbound from Tone** (Tone → Exotel): the same Tone IPs, as source addresses to allow.
- the transport you chose

Ask them to confirm **which source addresses their signalling actually comes from**. The media IPs
above are published; signalling can egress from a different address, and an `ipAcl` built from the
wrong list refuses every call with a `403`.

## Create the trunk in Tone

Use `ip_acl` — Exotel cannot present digest credentials.

```http
POST /v1/sip-trunks
{
  "name": "Exotel vSIP (Mumbai)",
  "inboundAuth": "ip_acl",
  "ipAcl": ["182.76.143.61/32", "122.15.8.184/32"],
  "outboundHost": "pstn.in2.exotel.com",
  "outboundPort": 443,
  "outboundTransport": "tls",
  "outboundNumberFormat": "e164",
  "callerIdPolicy": "did",
  "codecs": ["PCMA", "PCMU"],
  "customHeaders": { "X-Exotel-AccountSid": "your-account-sid" },
  "maxConcurrent": 20
}
```

Two fields are doing real work here.

**`customHeaders`** carries `X-Exotel-AccountSid`, which Exotel **requires** on an INVITE routed
into their network so they can find your tenant. It is the only `X-Exotel-*` header you may send:
do **not** add `X-Exotel-CallSid`, `X-Exotel-LegSid` or `X-Exotel-TrunkSid` — Exotel injects those,
and sending them is an error.

**`callerIdPolicy: "did"`** pins `From` to the trunk number. Exotel **rejects any outbound INVITE
whose `From` is not a registered Exophone**, so the permissive `any_e164` policy fails every call
on this carrier.

Then import each Exophone:

```http
POST /v1/sip-trunks/{id}/numbers
{ "e164": "+918044001234", "agentId": "…" }
```

## Log the call SID

On inbound legs Exotel injects `X-Exotel-CallSid` — the global call ID, and **the only join key
between your SIP capture and Exotel's own dashboard and CDR**. Tone records the inbound SIP headers
on the call, so when you open a ticket with Exotel you can hand them the SID from your own call log
instead of reconstructing it from timestamps.

## Testing

1. `POST /v1/sip-trunks/{id}/test` — a SIP `OPTIONS` ping to the PoP. Expect reachable, with an
   RTT in the low tens of milliseconds from Mumbai.
2. Call the Exophone from a mobile. Your agent should answer.
3. `POST /v1/calls` with the Exophone as `numberId`.

To watch the wire, Exotel's own suggestion is `sngrep` or Wireshark; SIPp works for synthetic calls.

## When it does not work

| What you see | Why |
|---|---|
| Inbound `403` from Tone | Exotel's signalling source is not in your `ipAcl`. Ask for the signalling addresses, not the media ones. |
| Outbound rejected by Exotel | `From` is not a registered Exophone — check `callerIdPolicy` is `did` and the number is live on the account. |
| Outbound tenant error at Exotel | `X-Exotel-AccountSid` missing or wrong in `customHeaders`. |
| Nothing at all, on TLS | You are on `5070` with `transport: tls`, or `443` with `tcp`. The two do not cross. |
| Works, then stalls at volume | 200 calls/min per trunk is an Exotel-side limit. Tone's `maxConcurrent` is separate and cannot raise it. |

## FQDN mode

If your side is not on a fixed address, Exotel can resolve an FQDN per call instead. It resolves
DNS on **every** call, so keep the TTL at 30–60 seconds, use **A/AAAA records — not a CNAME** — and
for TLS make sure the certificate CN or SAN matches the name Exotel dials. Tone's gateway runs on a
fixed Elastic IP, so you will not normally need this.

## Not this page

If you want a **Tone** number delivered to Exotel, or Exotel's Voicebot applet streaming to a Tone
agent, neither is this product — see [Inbound calls](/inbound-calls) and
[Tone Media Streams](/tone-media-streams).
