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}.
Region Base URL India (Mumbai) https://api.in.exotel.comSingapore https://api.exotel.com
Header Value 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"
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
Direction Requires Outbound Trunk + mapped DID + ACL and/or digest credentials Inbound destination-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
Method Path Purpose 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
Method Path Purpose 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
POST /v2/accounts/{account_sid}/trunks
▶ Try it live
Request parameters
Parameter Required Type Description trunk_nameYes String Alphanumeric + underscores only, max 16 chars nso_codeYes String Use "ANY-ANY" domain_nameYes String {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" } } }
Save response.data.trunk_sid. Nested resource URLs in the response already use hyphenated paths — reuse them as-is.
Try It
▸ POST Try it
Map phone number
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/phone-numbers
▶ Try it live
Request parameters
Parameter Required Type Description phone_numberYes String E.164 (+919876543210) modeNo String pstn (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" }
Save numeric mapping id for update/delete. Do not pass the E.164 string as the path id.
Try It
▸ POST Try it
Map ACL (whitelisted IP) — outbound
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/whitelisted-ips
▶ Try it live
Request parameters
Parameter Required Type Description ipYes String Public IPv4 maskNo Integer CIDR 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
▸ POST Try it
Create SIP digest credentials — outbound
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/credentials
▶ Try it live
Request parameters
Parameter Required Type Description user_nameYes String SIP digest username passwordYes String Strong password friendly_nameNo String Label, 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
▸ POST Try it
Scenario Auth Fixed-IP PBX / SBC whitelisted-ipsDynamic cloud egress credentialsHigh security Both
Map destination URI — inbound
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/destination-uris
▶ Try it live
Request parameters
Parameter Required Type Description destinationsYes Array List of destination objects destinations[].destinationYes String <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
▸ POST Try it
Manage & view APIs
List trunks
GET /v2/accounts/{account_sid}/trunks
▶ Try it live
Query parameters
Parameter Required Type Description page_sizeNo Integer Default 50 offsetNo Integer Default 0 trunk_sidNo String Filter 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
▸ GET Try it
Update trunk
PUT /v2/accounts/{account_sid}/trunks/{trunk_sid}
▶ Try it live
Request parameters
Parameter Required Type Description trunk_nameNo String Max 16 chars, alphanumeric + underscores auth_typeNo String e.g. IP whitelist nso_codeNo String Use "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
▸ PUT Try it
Delete trunk
DELETE /v2/accounts/{account_sid}/trunks?trunk_sid={trunk_sid}
▶ Try it live
curl -s -u " $EXOTEL_API_KEY : $EXOTEL_API_TOKEN " -X DELETE \ "https:// $EXOTEL_SUBDOMAIN /v2/accounts/ $EXOTEL_ACCOUNT_SID /trunks?trunk_sid=<trunk_sid>"
Irreversible. Removes phone mappings, ACLs, destination URIs, and credentials on the trunk.
Try It
▸ DELETE Try it
List phone numbers
GET /v2/accounts/{account_sid}/trunks/{trunk_sid}/phone-numbers
▶ Try it live
curl -s -u " $EXOTEL_API_KEY : $EXOTEL_API_TOKEN " \ "https:// $EXOTEL_SUBDOMAIN /v2/accounts/ $EXOTEL_ACCOUNT_SID /trunks/<trunk_sid>/phone-numbers"
Try It
▸ GET Try it
Update phone number mode
PUT /v2/accounts/{account_sid}/trunks/{trunk_sid}/phone-numbers/{phone_number_id}
▶ Try it live
Request parameters
Parameter Required Type Description phone_numberYes String E.164 — must match the mapping modeYes String pstn 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
▸ PUT Try it
Delete phone number mapping
DELETE /v2/accounts/{account_sid}/trunks/{trunk_sid}/phone-numbers?id={phone_number_id}
▶ Try it live
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
▸ DELETE Try it
Trunk map lookup (Exophone → trunk)
GET /v2/accounts/{account_sid}/trunk-maps
▶ Try it live
Query parameters
Parameter Required Type Description exophoneYes String DID in E.164 trunk_sidNo String Optional 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
▸ GET Try it
List ACLs
GET /v2/accounts/{account_sid}/trunks/{trunk_sid}/whitelisted-ips
▶ Try it live
curl -s -u " $EXOTEL_API_KEY : $EXOTEL_API_TOKEN " \ "https:// $EXOTEL_SUBDOMAIN /v2/accounts/ $EXOTEL_ACCOUNT_SID /trunks/<trunk_sid>/whitelisted-ips"
Try It
▸ GET Try it
Update whitelisted IP
PUT /v2/accounts/{account_sid}/trunks/{trunk_sid}/whitelisted-ips/{whitelist_entry_id}
▶ Try it live
Request parameters
Parameter Required Type Description ipYes String IPv4 maskYes Integer CIDR 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
▸ PUT Try it
Delete whitelisted IP
DELETE /v2/accounts/{account_sid}/trunks/{trunk_sid}/whitelisted-ips?id={whitelist_entry_id}
▶ Try it live
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
▸ DELETE Try it
List destination URIs
GET /v2/accounts/{account_sid}/trunks/{trunk_sid}/destination-uris
▶ Try it live
curl -s -u " $EXOTEL_API_KEY : $EXOTEL_API_TOKEN " \ "https:// $EXOTEL_SUBDOMAIN /v2/accounts/ $EXOTEL_ACCOUNT_SID /trunks/<trunk_sid>/destination-uris"
Try It
▸ GET Try it
Update destination URI
PUT /v2/accounts/{account_sid}/trunks/{trunk_sid}/destination-uris/{destination_id}
▶ Try it live
Request parameters
Parameter Required Type Description priorityNo Integer Lower = higher priority (default 0) weightNo Integer Higher = 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
▸ PUT Try it
Delete destination URI
DELETE /v2/accounts/{account_sid}/trunks/{trunk_sid}/destination-uris?id={destination_id}
▶ Try it live
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
▸ DELETE Try it
List credentials
GET /v2/accounts/{account_sid}/trunks/{trunk_sid}/credentials
▶ Try it live
curl -s -u " $EXOTEL_API_KEY : $EXOTEL_API_TOKEN " \ "https:// $EXOTEL_SUBDOMAIN /v2/accounts/ $EXOTEL_ACCOUNT_SID /trunks/<trunk_sid>/credentials"
Try It
▸ GET Try it
Update SIP credential
PUT /v2/accounts/{account_sid}/trunks/{trunk_sid}/credentials/{credential_id}
▶ Try it live
Request parameters
Parameter Required Type Description user_nameNo String New digest username passwordNo String New password friendly_nameNo String Label, 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
▸ PUT Try it
Delete credential
DELETE /v2/accounts/{account_sid}/trunks/{trunk_sid}/credentials?id={credential_id}
▶ Try it live
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
▸ DELETE Try it
List trunk settings
GET /v2/accounts/{account_sid}/trunks/{trunk_sid}/settings
▶ Try it live
curl -s -u " $EXOTEL_API_KEY : $EXOTEL_API_TOKEN " \ "https:// $EXOTEL_SUBDOMAIN /v2/accounts/ $EXOTEL_ACCOUNT_SID /trunks/<trunk_sid>/settings"
Try It
▸ GET Try it
Set trunk alias (caller ID)
POST /v2/accounts/{account_sid}/trunks/{trunk_sid}/settings
▶ Try it live
Request parameters
Parameter Required Type Description settingsYes Array Setting objects settings[].nameYes String Use trunk_external_alias settings[].valueYes String Caller 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
▸ POST Try it
Delete trunk setting
DELETE /v2/accounts/{account_sid}/trunks/{trunk_sid}/settings?name={setting_name}
▶ Try it live
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
▸ DELETE Try it
Network & errors