Dynamic SIP Trunking
Connect your SIP system to Exotel's PSTN infrastructure via REST API. Create trunks, whitelist IPs, map phone numbers, and configure routing โ all programmatically.
How it worksโ
Outbound: Your SIP system โ Exotel SIP trunk โ PSTN
Inbound: PSTN โ Exotel โ Flow (Connect applet) โ SIP trunk โ Your SIP system
Call directionsโ
| Direction | Path | Requires |
|---|---|---|
| Outbound (SIP โ PSTN) | Your SIP โ Exotel โ PSTN | Whitelisted IP (ACL) + phone number mapped to trunk |
| Inbound (PSTN โ SIP) | PSTN โ Exotel Flow โ SIP trunk โ Your system | Destination URI + Flow with Connect applet using sip:<trunk_sid> |
| Bidirectional | Both above | Both above |
Routing modesโ
| Mode | Use when |
|---|---|
pstn | Standard PSTN inbound/outbound (default) |
flow | Route calls through a Voice AI / StreamKit flow |
Quick setupโ
1. Create trunk โ get trunk_sid
2. Map phone number โ get phone_number_id
3. Whitelist your IP โ enables outbound
4. Set destination URI โ enables inbound
API referenceโ
Base URLs
| Region | URL |
|---|---|
| Mumbai | https://api.in.exotel.com |
| Singapore | https://api.exotel.com |
Auth: HTTP Basic โ API key as username, API token as password.
Rate limit: 200 requests/minute.
All endpoints are prefixed with /v2/accounts/{account_sid}.
Create trunkโ
POST /v2/accounts/{account_sid}/trunks
| Parameter | Required | Description |
|---|---|---|
trunk_name | Yes | Alphanumeric + underscores, max 16 chars |
nso_code | Yes | Use "any any" |
domain_name | Yes | {account_sid}.pstn.exotel.com |
curl -X POST \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks' \
-H 'Content-Type: application/json' \
-d '{
"trunk_name": "outbound_trunk",
"nso_code": "any any",
"domain_name": "<account_sid>.pstn.exotel.com"
}'
{
"trunk_sid": "TKxxxxxxxxxxxxxxxx",
"trunk_name": "outbound_trunk",
"status": "active",
"auth_type": "ip whitelist",
"domain_name": "<account_sid>.pstn.exotel.com",
"date_created": "2026-05-14T10:00:00Z"
}
Save trunk_sid โ required for all subsequent API calls.
Map phone numberโ
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/phone_numbers
| Parameter | Required | Description |
|---|---|---|
phone_number | Yes | E.164 format (+919876543210) |
mode | No | pstn (default) or flow (Voice AI) |
curl -X POST \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/phone_numbers' \
-H 'Content-Type: application/json' \
-d '{
"phone_number": "+919876543210",
"mode": "pstn"
}'
{
"id": 41523,
"phone_number": "+919876543210",
"trunk_sid": "TKxxxxxxxxxxxxxxxx",
"mode": "pstn"
}
Save the numeric id โ needed for mode updates.
Whitelist IP (outbound)โ
Registers your server's IP for outbound call authentication.
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/whitelisted_ips
| Parameter | Required | Description |
|---|---|---|
ip | Yes | Your server's public IPv4 address |
mask | No | CIDR subnet mask (default: 32) |
curl -X POST \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/whitelisted_ips' \
-H 'Content-Type: application/json' \
-d '{
"ip": "44.248.146.11",
"mask": 32
}'
{
"id": 123,
"ip": "44.248.146.11",
"mask": 32,
"trunk_sid": "TKxxxxxxxxxxxxxxxx"
}
Set destination URI (inbound)โ
Configures where Exotel routes incoming calls.
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/destination_uris
| Parameter | Required | Description |
|---|---|---|
destinations[].destination | Yes | SIP URI: <ip_or_fqdn>:<port>;transport=<tls|tcp> |
Supported transports: tls (port 5061, recommended) ยท tcp (port 5060)
# IP-based
curl -X POST \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/destination_uris' \
-H 'Content-Type: application/json' \
-d '{
"destinations": [
{ "destination": "44.248.146.11:5061;transport=tls" }
]
}'
# FQDN-based
curl -X POST \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/destination_uris' \
-H 'Content-Type: application/json' \
-d '{
"destinations": [
{ "destination": "sip.yourcompany.com:5061;transport=tls" }
]
}'
{
"id": 456,
"destination": "sip:44.248.146.11:5061;transport=tls",
"type": "public",
"priority": 0,
"weight": 1,
"trunk_sid": "TKxxxxxxxxxxxxxxxx"
}
SIP digest credentialsโ
Use instead of (or alongside) IP whitelisting for cloud platforms with dynamic IPs (e.g. ElevenLabs, LiveKit).
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/credentials
| Parameter | Required | Description |
|---|---|---|
user_name | Yes | SIP digest username |
password | Yes | Strong password |
friendly_name | No | Label, max 32 chars |
curl -X POST \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/credentials' \
-H 'Content-Type: application/json' \
-d '{
"user_name": "voice_ai_user",
"password": "strong_password_here",
"friendly_name": "elevenlabs_prod"
}'
List credentials
curl 'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/credentials'
Delete credentials
curl -X DELETE \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/credentials?id=<credential_id>'
Update phone number modeโ
Switch a mapped number between PSTN and Flow (Voice AI) routing.
PUT /v2/accounts/{account_sid}/trunks/{trunk_sid}/phone_numbers/{phone_number_id}
curl -X PUT \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/phone_numbers/41523' \
-H 'Content-Type: application/json' \
-d '{
"phone_number": "+919876543210",
"mode": "flow"
}'
Use the numeric id from the Map Phone Number response, not the phone number itself.
Set caller ID (trunk alias)โ
Sets the number displayed to called parties on outbound calls.
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/settings
curl -X POST \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks/<trunk_sid>/settings' \
-H 'Content-Type: application/json' \
-d '{
"settings": [
{ "name": "trunk_external_alias", "value": "+919876543210" }
]
}'
Delete trunkโ
DELETE /v2/accounts/{account_sid}/trunks?trunk_sid={trunk_sid}
curl -X DELETE \
'https://<api_key>:<api_token>@api.in.exotel.com/v2/accounts/<account_sid>/trunks?trunk_sid=<trunk_sid>'
Permanently deletes the trunk and all associated phone numbers, ACLs, and destination URIs.
IP whitelist vs credentialsโ
| Scenario | Method |
|---|---|
| On-premises PBX / SBC with fixed IP | IP whitelist only |
| Cloud AI platforms (ElevenLabs, LiveKit) | Credentials only |
| High-security production | Both |
Network & firewallโ
For the full list of SIP signaling endpoints, inbound source IPs, media IP ranges, and firewall rules, refer to the official source of truth:
Network & Firewall Configuration โ
If calls connect but have no audio or one-way audio โ UDP 10 000โ40 000 is likely blocked on your firewall.
SIP error codesโ
4xx โ Client errorsโ
| Code | Meaning | Fix |
|---|---|---|
400 | Bad request | Review SIP headers / SDP |
401 | Unauthorized | Check digest credentials |
403 | Forbidden | IP not whitelisted โ check ACL |
404 | Not found | Verify phone number mapping |
408 | Request timeout | Check firewall / reachability |
415 | Unsupported media | Enable G.711 A-Law; disable other codecs |
480 | Temporarily unavailable | Check PBX/SBC availability |
484 | Address incomplete | Use E.164 format for numbers |
486 | Busy | Destination busy โ normal |
488 | Not acceptable | SDP/codec mismatch โ enable G.711 A-Law only |
5xx โ Server errorsโ
| Code | Meaning | Fix |
|---|---|---|
500 | Server error | Retry |
502 | Bad gateway | Upstream routing issue โ retry |
503 | Service unavailable | Check network / routing |
504 | Gateway timeout | Check firewall latency |
Audio issues (no SIP error)โ
| Symptom | Cause | Fix |
|---|---|---|
| No audio both ways | RTP blocked | Open UDP 10 000โ40 000 |
| One-way audio | NAT / firewall | Check public IP in SDP |
| Audio drops mid-call | RTP idle timeout | Adjust firewall timeout |
API error codesโ
| Code | HTTP | Meaning | Fix |
|---|---|---|---|
1000 | 404 | Resource not found | Verify trunk SID / phone number ID |
1001 | 400 | Mandatory parameter missing | Check all required fields |
1002 | 400 | Invalid parameter | Validate formats (E.164, IP, etc.) |
1007 | 400 | Malformed JSON | Fix JSON syntax |
1008 | 409 | Duplicate resource | Already configured โ safe to ignore |
1011 | 415 | Wrong content type | Add Content-Type: application/json |
Relatedโ
- SIP Trunking Overview โ Static SIP trunking setup
- Flow API Configuration โ API-driven Voice AI setup
- Manage ExoTrunks โ SIP trunk management