Skip to main content

Dynamic SIP Trunking API

SIP Trunking is the product that connects your PBX, SBC, or SIP platform to Exotel PSTN.
Dynamic SIP Trunking is the REST API used to create and manage those trunks.

Use these APIs to make outbound calls (SIP → PSTN), receive inbound calls (PSTN → SIP), and integrate with Exotel Flows / StreamKit Voice AI.

Samples: Postman · GitHub


Base URL and authentication​

All APIs use HTTP Basic Auth. Prefix every path with /v2/accounts/{account_sid}.

RegionBase URL
India (Mumbai)https://api.in.exotel.com
Singaporehttps://api.exotel.com
HeaderValue
AuthorizationBasic (api_key:api_token)
Content-Typeapplication/json

Rate limit: 200 requests/minute.

export EXOTEL_API_KEY="your_api_key"
export EXOTEL_API_TOKEN="your_api_token"
export EXOTEL_ACCOUNT_SID="your_account_sid"
export EXOTEL_SUBDOMAIN="api.in.exotel.com" # or api.exotel.com

Response envelope​

Successful calls return this shape (field names exact):

{
"request_id": "10a67da360d446378d5c2b66407b7f18",
"method": "POST",
"http_code": 200,
"response": {
"code": 200,
"error_data": null,
"status": "success",
"data": { }
}
}

List endpoints wrap items in response[] and may include metadata (page_size, first_page_uri, prev_page_uri, next_page_uri).


Workflow​

Create trunk → Map phone-numbers → whitelisted-ips and/or credentials → destination-uris
DirectionRequires
OutboundTrunk + mapped DID + ACL and/or digest credentials
Inbounddestination-uris + Connect applet sip:<trunk_sid>

Number mode: pstn (default) · flow (Voice AI / StreamKit). See Call directions.


Endpoint index​

Paths below are relative to /v2/accounts/{account_sid}.

Setup​

MethodPathPurpose
POST/trunksCreate trunk
POST/trunks/{trunk_sid}/phone-numbersMap DID
POST/trunks/{trunk_sid}/whitelisted-ipsAdd ACL
POST/trunks/{trunk_sid}/credentialsCreate digest credentials
POST/trunks/{trunk_sid}/destination-urisMap inbound URI

Manage & view​

MethodPathPurpose
GET/trunksList trunks
PUT/trunks/{trunk_sid}Update trunk
DELETE/trunks?trunk_sid=Delete trunk
GET/trunks/{trunk_sid}/phone-numbersList mapped numbers
PUT/trunks/{trunk_sid}/phone-numbers/{id}Update mode
DELETE/trunks/{trunk_sid}/phone-numbers?id=Unmap number
GET/trunk-maps?exophone=Lookup DID → trunk
GET/trunks/{trunk_sid}/whitelisted-ipsList ACLs
PUT/trunks/{trunk_sid}/whitelisted-ips/{id}Update ACL
DELETE/trunks/{trunk_sid}/whitelisted-ips?id=Delete ACL
GET/trunks/{trunk_sid}/destination-urisList URIs
PUT/trunks/{trunk_sid}/destination-uris/{id}Update priority/weight
DELETE/trunks/{trunk_sid}/destination-uris?id=Delete URI
GET/trunks/{trunk_sid}/credentialsList credentials
PUT/trunks/{trunk_sid}/credentials/{id}Update credential
DELETE/trunks/{trunk_sid}/credentials?id=Delete credential
GET/trunks/{trunk_sid}/settingsList settings
POST/trunks/{trunk_sid}/settingsSet caller ID alias
DELETE/trunks/{trunk_sid}/settings?name=Delete setting

Setup APIs​

Create trunk​

Request parameters​

ParameterRequiredTypeDescription
trunk_nameYesStringAlphanumeric + underscores only, max 16 chars
nso_codeYesStringUse "ANY-ANY"
domain_nameYesString{account_sid}.pstn.exotel.com

Example request​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks" \
-H "Content-Type: application/json" \
-d '{
"trunk_name": "outbound_trunk",
"nso_code": "ANY-ANY",
"domain_name": "'"$EXOTEL_ACCOUNT_SID"'.pstn.exotel.com"
}'

Example response​

{
"request_id": "10a67da360d446378d5c2b66407b7f18",
"method": "POST",
"http_code": 200,
"response": {
"code": 200,
"error_data": null,
"status": "success",
"data": {
"trunk_sid": "trmum1f708622631150902801a1n",
"trunk_name": "outbound_trunk",
"status": "active",
"domain_name": "ameyo5m.pstn.exotel.com",
"auth_type": "IP-WHITELIST",
"nso_code": "ANY-ANY",
"phone_numbers": "/v2/accounts/ameyo5m/trunks/trmum1f708622631150902801a1n/phone-numbers",
"whitelisted_ips": "/v2/accounts/ameyo5m/trunks/trmum1f708622631150902801a1n/whitelisted-ips",
"destination_uris": "/v2/accounts/ameyo5m/trunks/trmum1f708622631150902801a1n/destination-uris",
"credentials": "/v2/accounts/ameyo5m/trunks/trmum1f708622631150902801a1n/credentials"
}
}
}
note

Save response.data.trunk_sid. Nested resource URLs in the response already use hyphenated paths — reuse them as-is.

Try It​


Map phone number​

Request parameters​

ParameterRequiredTypeDescription
phone_numberYesStringE.164 (+919876543210)
modeNoStringpstn (default) or flow (StreamKit / Voice AI)

Example request​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/phone-numbers" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+919876543210",
"mode": "pstn"
}'

Example response (data)​

{
"id": "41512",
"phone_number": "+919876543210",
"trunk_sid": "trmum1f708622631150902801a1n",
"mode": "pstn",
"date_created": "2026-01-23T10:26:54Z",
"date_updated": "2026-01-23T10:26:54Z"
}
note

Save numeric mapping id for update/delete. Do not pass the E.164 string as the path id.

Try It​


Map ACL (whitelisted IP) — outbound​

Request parameters​

ParameterRequiredTypeDescription
ipYesStringPublic IPv4
maskNoIntegerCIDR mask (default 32)
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/whitelisted-ips" \
-H "Content-Type: application/json" \
-d '{ "ip": "44.248.146.11", "mask": 32 }'

Try It​


Create SIP digest credentials — outbound​

Request parameters​

ParameterRequiredTypeDescription
user_nameYesStringSIP digest username
passwordYesStringStrong password
friendly_nameNoStringLabel, max 32 chars
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/credentials" \
-H "Content-Type: application/json" \
-d '{
"user_name": "SIP_USER",
"password": "strong_password_here",
"friendly_name": "voice_ai_prod"
}'

Try It​

ScenarioAuth
Fixed-IP PBX / SBCwhitelisted-ips
Dynamic cloud egresscredentials
High securityBoth

Map destination URI — inbound​

Request parameters​

ParameterRequiredTypeDescription
destinationsYesArrayList of destination objects
destinations[].destinationYesString<ip_or_fqdn>:<port>;transport=tls or tcp

Prefer TLS on port 5061.

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/destination-uris" \
-H "Content-Type: application/json" \
-d '{
"destinations": [
{ "destination": "44.248.146.11:5061;transport=tls" }
]
}'
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/destination-uris" \
-H "Content-Type: application/json" \
-d '{
"destinations": [
{ "destination": "sip.yourcompany.com:5061;transport=tls" }
]
}'

Save destination id from response.data for update/delete. Inbound Connect applet: Connect Applet inbound.

Try It​


Manage & view APIs​

List trunks​

Query parameters​

ParameterRequiredTypeDescription
page_sizeNoIntegerDefault 50
offsetNoIntegerDefault 0
trunk_sidNoStringFilter to one trunk
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks?page_size=50&offset=0"

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks?trunk_sid=<trunk_sid>"

Try It​


Update trunk​

Request parameters​

ParameterRequiredTypeDescription
trunk_nameNoStringMax 16 chars, alphanumeric + underscores
auth_typeNoStringe.g. IP whitelist
nso_codeNoStringUse "ANY-ANY"
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X PUT \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>" \
-H "Content-Type: application/json" \
-d '{ "trunk_name": "my_pbx_trunk" }'

Try It​


Delete trunk​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X DELETE \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks?trunk_sid=<trunk_sid>"
warning

Irreversible. Removes phone mappings, ACLs, destination URIs, and credentials on the trunk.

Try It​


List phone numbers​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/phone-numbers"

Try It​


Update phone number mode​

Request parameters​

ParameterRequiredTypeDescription
phone_numberYesStringE.164 — must match the mapping
modeYesStringpstn or flow

phone_number_id is the numeric mapping id (e.g. 41523).

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X PUT \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/phone-numbers/41523" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+919876543210",
"mode": "flow"
}'

Try It​


Delete phone number mapping​

Id is a query parameter (?id=), not a path segment.

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X DELETE \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/phone-numbers?id=41523"

Try It​


Trunk map lookup (Exophone → trunk)​

Query parameters​

ParameterRequiredTypeDescription
exophoneYesStringDID in E.164
trunk_sidNoStringOptional filter
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunk-maps?exophone=%2B919876543210"
{
"exophone": "+919876543210",
"trunk_sid": "trmum1f708622631150902801a1n",
"phone_number_id": "41512",
"mode": "pstn"
}

Try It​


List ACLs​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/whitelisted-ips"

Try It​


Update whitelisted IP​

Request parameters​

ParameterRequiredTypeDescription
ipYesStringIPv4
maskYesIntegerCIDR mask
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X PUT \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/whitelisted-ips/1153" \
-H "Content-Type: application/json" \
-d '{ "ip": "44.248.146.11", "mask": 32 }'

Try It​


Delete whitelisted IP​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X DELETE \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/whitelisted-ips?id=1153"

Try It​


List destination URIs​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/destination-uris"

Try It​


Update destination URI​

Request parameters​

ParameterRequiredTypeDescription
priorityNoIntegerLower = higher priority (default 0)
weightNoIntegerHigher = more traffic (default 1)
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X PUT \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/destination-uris/2543" \
-H "Content-Type: application/json" \
-d '{ "priority": 0, "weight": 5 }'

Try It​


Delete destination URI​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X DELETE \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/destination-uris?id=2543"

Try It​


List credentials​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/credentials"

Try It​


Update SIP credential​

Request parameters​

ParameterRequiredTypeDescription
user_nameNoStringNew digest username
passwordNoStringNew password
friendly_nameNoStringLabel, max 32 chars

Credential id is in the path. Delete uses ?id= instead.

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X PUT \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/credentials/1234" \
-H "Content-Type: application/json" \
-d '{
"friendly_name": "voice_ai_prod",
"password": "replace_with_strong_password"
}'

Try It​


Delete credential​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X DELETE \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/credentials?id=1234"

Try It​


List trunk settings​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/settings"

Try It​


Set trunk alias (caller ID)​

Request parameters​

ParameterRequiredTypeDescription
settingsYesArraySetting objects
settings[].nameYesStringUse trunk_external_alias
settings[].valueYesStringCaller ID in E.164
curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/settings" \
-H "Content-Type: application/json" \
-d '{
"settings": [
{ "name": "trunk_external_alias", "value": "+919876543210" }
]
}'

Try It​


Delete trunk setting​

curl -s -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X DELETE \
"https://$EXOTEL_SUBDOMAIN/v2/accounts/$EXOTEL_ACCOUNT_SID/trunks/<trunk_sid>/settings?name=trunk_external_alias"

Try It​


Network & errors​