Overview

Exotel's RESTful APIs make it easy to integrate Voice & SMS in your web or mobile application. Think,

  • In-app calling while booking a cab
  • Click to call features on websites
  • Passwordless authentication
  • Customer notification via SMS

The possibilities are endless! Exotel's APIs allow you to programmatically control a call by playing personalised greetings, diverting users to a unique call flow, pushing call information, getting call recordings, etc. The APIs are designed according to REST principles. Exotel's REST APIs are served over HTTPS and HTTP. However, we highly recommend communicating over HTTPS.

Images provided below are a schematic representation of how Exotel works when an outgoing or incoming call occurs.

Call legCall legCall leg

Authentication

Each API request will have to contain request headers that include your access token to authenticate the request. Don't have an access token? You will find your access token in the API Settings Tab of your Exotel Dashboard.

HTTP requests to the REST API are protected with HTTP Basic authentication. You will use your Exotel account SID as the username and your auth token as the password for HTTP Basic authentication. You can find your account SID and auth token on your Exotel Dashboard.

Base URL: https://api.exotel.com/v1/Accounts/


Rate Limits

To keep you in compliance, Exotel maintains the appropriate rate limits:

APIValue
VoiceAll Voice APIs are rate limited to 200 calls per minute. Once this limit has been crossed, your requests will be rejected with an HTTP 429 'Too Many Requests' code
SMSAll SMS APIs are rate limited to 200 SMSes per minute. Once this limit has been crossed, your requests will be rejected with an HTTP 429 'Too Many Requests' code

HTTP Status Codes

Exotel uses standard HTTP status codes to communicate errors:

Status CodeValue
200OK - Everything went as planned.
202Accepted - Request accepted.
400Bad Request - Something in your header or request body was malformed.
401Unauthorised - Necessary credentials were either missing or invalid.
402Payment Required - The action is not available on your plan, or you have exceeded usage limits for your current plan.
403Your credentials are valid, but you don’t have access to the requested resource.
404Not Found - The object you’re requesting doesn’t exist.
409Conflict - You might be trying to update the same resource concurrently.
429Too Many Requests - You are calling our APIs more frequently than we allow.
5xxServer Errors - Something went wrong on our end. Please try again.

Outgoing call to connect two numbers

This API will connect two numbers. It connects From Number first. Once the person at the From end picks up the phone, it will connect to the number provided as To. You can choose which number should be connected first by adding that number in the From field. An HTTP POST request is made to

POST

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

The following are the POST parameters:

Parameter NameMandatory/OptionalValue
FromMandatoryThe phone number that will be called first. Preferably in E.164 format. If not set, our system will try to match it with a country and make a call. If landline number, prefix it with STD code; Ex: 080XXXX2400
ToMandatoryYour customer's phone number. If landline number, prefix it with STD code; Ex: 080XXXX2400
CallerIdMandatoryThis is your ExoPhone/Exotel Virtual Number (pick one from here)
CallTypeOptionaltrans - for Transactional Calls
TimeLimitOptionalThe time limit (in seconds) that you want this call to last. The call will be cut after this time
TimeOutOptionalThe time (in seconds) to ring the called parties (both first and second call leg)
WaitUrl NewOptional

Play this audio to the caller. When the first leg (From) has to wait for the other leg (To) to pick up the call, the audio file specified in this parameter will be played.

Please refer this article to understand the format specifications of the audio file to be played (wav is only supported).

Guidelines on usage:

  • The audio file size is recommended to be less than 2MB. Please note, Exotel will cache the wav file. During the first few call attempts of setting this parameter, user might hear normal ringing tone for first 5 seconds (for a ~2MB file). This is only temporary for initial few calls and once the audio file is cached, audio will be played out smoothly.
  • In case you decide to change the audio file later, the WaitUrl should be different (as Exotel will cache audio file based on URL). You can do so by hosting the audio file with a different name.
  • When using this parameter, it is recommended to set the TimeOut parameter as well.
Example: "http://{your_hosted_endpoint}/{audio file name}.wav"

StatusCallbackOptionalWhen the call completes, an HTTP POST will be made to the provided URL with the following four parameters:
  • CallSid - an alpha-numeric unique identifier
  • Status - one of: completed, failed, busy, no-answer
  • RecordingUrl - link to the call recording (if it exists)
  • DateUpdated - time when the call state was updated last
 curl -X POST https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect \
 -d "From=XXXXX30240" \
 -d "To=XXXXX40682" \
 -d "CallerId=0XXXXXX4890"
            
var request = require('request');

var dataString = 'From=XXXXX30240&To=XXXXX40682&CallerId=0XXXXXX4890';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect',
    method: 'POST',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'From' => 'XXXXX30240',
    'To' => 'XXXXX40682',
    'CallerId' => '0XXXXXX4890'
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect")
request = Net::HTTP::Post.new(uri)
request.set_form_data(
  "From" => "XXXXX30240",
  "To" => "XXXXX40682",
  "CallerId" => "0XXXXXX4890",
)

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = {
  'From': 'XXXXX30240',
  'To': 'XXXXX40682',
  'CallerId': '0XXXXXX4890'
}

requests.post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The Sid is the unique identifier of the call, and it will be useful to log this for future debugging
  • the HTTP body will contain an XML/JSON similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
    <Call>
        <Sid>06caf2045009d50fbb1da5b5926d2e2f</Sid>
        <ParentCallSid/>
        <DateCreated>2017-03-03 11:00:19</DateCreated>
        <DateUpdated>2017-03-03 11:00:19</DateUpdated>
        <AccountSid>Exotel</AccountSid>
        <To>0XXXXX40682</To>
        <From>0XXXXX30240</From>
        <PhoneNumberSid>0XXXXXX4890</PhoneNumberSid>
        <Status>in-progress</Status>
        <StartTime>2017-03-03 11:00:19</StartTime>
        <EndTime/>
        <Duration/>
        <Price/>
        <Direction>outbound-api</Direction>
        <AnsweredBy/>
        <ForwardedFrom/>
        <CallerName/>
        <Uri>/v1/Accounts/Exotel/Calls/06caf2045009d50fbb1da5b5926d2e2f</Uri>
        <RecordingUrl/>
    </Call>
</TwilioResponse>
            
{
  "Call": {
    "Sid": "c5797dcbaaeed7678c4062a4a3ed2f8a",
    "ParentCallSid": null,
    "DateCreated": "2017-03-03 10:48:33",
    "DateUpdated": "2017-03-03 10:48:33",
    "AccountSid": "Exotel",
    "To": "0XXXXX38847",
    "From": "0XXXXX30240",
    "PhoneNumberSid": "0XXXXXX4890",
    "Status": "in-progress",
    "StartTime": "2017-03-03 10:48:33",
    "EndTime": null,
    "Duration": null,
    "Price": null,
    "Direction": "outbound-api",
    "AnsweredBy": null,
    "ForwardedFrom": null,
    "CallerName": null,
    "Uri": "/v1/Accounts/Exotel/Calls.json/c5797dcbaaeed7678c4062a4a3ed2f8a",
    "RecordingUrl": null
  }
}


            

Description of parameters mentioned in the above response:

Parameter NameType & Value
Sidstring; an alpha-numeric unique identifier of the call
DateCreatedTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the user initiated the API
DateUpdatedTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the status of the call was last updated in our system
AccountSidExotel account SID
ToYour customer's phone number
FromThe phone number that will be called first
PhoneNumberSidThis is your ExoPhone/Exotel Virtual Number
StatusWhen the call completes, an HTTP POST will be made to the URL mentioned with the following parameters:
  • queued - The call is ready and waiting in line before going out
  • in-progress - The call was answered and is currently in progress
  • completed - The call was answered and has ended normally
  • failed - The call could not be completed as dialled, most likely because the phone number was non-existent
  • busy - The caller received a busy signal
  • no-answer - The call ended without being answered
StartTimeTime in format YYYY-MM-DD HH:mm:ss; Date and time when the call request was initiated to the operator
EndTimeTime in format YYYY-MM-DD HH:mm:ss; Date and time when the call was completed
DurationCall duration in seconds
PriceDouble; If present, this will be the amount (in INR or USD) you have been charged for the call
Direction
  • inbound - Incoming call
  • outbound-dial - Outbound calls from Exotel dashboard
  • outbound-api - All other Outbound calls (API, campaign etc.)
AnsweredByhuman
UriUri is the path of the CallSid
RecordingUrlLink to the call recording

Outgoing call to connect number to a call flow

This API will first call the From number, and once they pick up the phone, it will connect them to a call flow (aka applet) that you have created in the system - like your landing app, or any other app that can play a greeting, have IVR, etc. For more details on setting up your flow, please refer Appplet documentation. An HTTP POST request is made to

POST

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

The following are the POST parameters:

Parameter NameMandatory/OptionalValue
FromMandatoryThe phone number that will be called first. Preferably in E.164 format. If not set, our system will try to match it with a country and make a call. If landline number, prefix it with STD code; Ex: 0XXXXXX2400
CallerIdMandatoryThis is your ExoPhone (pick one from here)
UrlMandatoryhttp://my.exotel.com/{your_sid}/exoml/start_voice/{app_id} where app_id is the identifier of the flow (or applet) that you want to connect to once the From number picks up the call. You can get the app_id from your Exotel Dashboard
CallTypeOptionaltrans - for Transactional Calls
TimeLimitOptionalThe time limit (in seconds) that you want this call to last. The call will be cut after this time
TimeOutOptionalThe time (in seconds) to ring the called parties (both first and second call leg)
StatusCallbackOptionalWhen the call completes, an HTTP POST will be made to the provided URL with the following four parameters:
  • CallSid - an alpha-numeric unique identifier
  • Status - one of: completed, failed, busy, no-answer
  • RecordingUrl - link to the call recording (if it exists)
  • DateUpdated - time when the call state was updated last
CustomFieldOptionalAny application specific value that will be passed back as a parameter while doing a GET request to the URL mentioned in your Passthru Applet or Greetings Applet.
 curl -X POST https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect \
 -d "From=XXXXX30240" \
 -d "CallerId=0XXXXXX4890" \
 -d "Url=http://my.exotel.com/Exotel/exoml/start_voice/926"
            
var request = require('request');

var dataString = 'From=XXXXX30240&CallerId=0XXXXXX4890&Url=http://my.exotel.com/Exotel/exoml/start_voice/926';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect',
    method: 'POST',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'From' => 'XXXXX30240',
    'CallerId' => '0XXXXXX4890',
    'Url' => 'http://my.exotel.com/Exotel/exoml/start_voice/926'
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect")
request = Net::HTTP::Post.new(uri)
request.set_form_data(
  "From" => "XXXXX30240",
  "CallerId" => "0XXXXXX4890",
  "Url" => "http://my.exotel.com/Exotel/exoml/start_voice/926",
)

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = {
  'From': 'XXXXX30240',
  'CallerId': '0XXXXXX4890',
  'Url': 'http://my.exotel.com/Exotel/exoml/start_voice/926'
}

requests.post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/connect', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The Sid is the unique identifier of the call, and it will be useful to log this for future debugging
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
 <Call>
  <Sid>db05188d0f6cf980cdcef8992c2b8cd4</Sid>
  <ParentCallSid/>
  <DateCreated>2017-02-22 04:35:19</DateCreated>
  <DateUpdated>2017-02-22 04:35:19</DateUpdated>
  <AccountSid>Exotel</AccountSid>
  <To>0XXXXX40682</To>
  <From>0XXXXX30240</From>
  <PhoneNumberSid>0XXXXXX4890</PhoneNumberSid>
  <Status>in-progress</Status>
  <StartTime>2017-02-22 04:35:19</StartTime>
  <EndTime/>
  <Duration/>
  <Price/>
  <Direction>outbound-api</Direction>
  <AnsweredBy/>
  <ForwardedFrom/>
  <CallerName/>
  <Uri>/v1/Accounts/Exotel/Calls/db05188d0f6cf980cdcef8992c2b8cd4</Uri>
  <RecordingUrl/>
 </Call>
</TwilioResponse>
            
{
  "Call": {
    "Sid": "80bfbec2d78bbbf10fb851f4fa165211",
    "ParentCallSid": null,
    "DateCreated": "2017-03-03 12:30:24",
    "DateUpdated": "2017-03-03 12:30:27",
    "AccountSid": "Exotel",
    "To": "0XXXXX40682",
    "From": "0XXXXX30240",
    "PhoneNumberSid": "0XXXXXX4890",
    "Status": "in-progress",
    "StartTime": "2017-03-03 12:30:27",
    "EndTime": null,
    "Duration": null,
    "Price": null,
    "Direction": "outbound-api",
    "AnsweredBy": null,
    "ForwardedFrom": null,
    "CallerName": null,
    "Uri": "/v1/Accounts/Exotel/Calls.json/80bfbec2d78bbbf10fb851f4fa165211",
    "RecordingUrl": null
  }
}


            

Description of parameters mentioned in the above response:

Parameter NameType & Value
Sidstring; an alpha-numeric unique identifier of the call
DateCreatedTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the user initiated the API
DateUpdatedTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the status of the call was last updated in our system
AccountSidExotel account SID
ToYour customer's phone number
FromThe phone number that will be called first
PhoneNumberSidThis is your ExoPhone/Exotel Virtual Number
StatusWhen the call completes, an HTTP POST will be made to the URL mentioned with the following parameters:
  • queued - The call is ready and waiting in line before going out
  • in-progress - The call was answered and is currently in progress
  • completed - The call was answered and has ended normally
  • failed - The call could not be completed as dialed, most likely because the phone number was non-existent
  • busy - The caller received a busy signal
  • no-answer - The call ended without being answered
StartTimeTime in format YYYY-MM-DD HH:mm:ss; Date and time when the call request was initiated to the operator
EndTimeTime in format YYYY-MM-DD HH:mm:ss; Date and time when the call was completed
DurationCall duration in seconds
PriceDouble; If present, this will be the amount (in INR or USD) you have been charged for the call
Direction
  • inbound
  • outbound-dial - Outbound calls from Exotel dashboard
  • outbound-api - All other Outbound calls (API, Campaign etc.)
AnsweredByhuman
UriUri is the path of the CallSid
RecordingUrlLink to the call recording

Incoming call

When an incoming call lands on your ExoPhone, a call flow is initiated. To configure a call flow for your ExoPhone, please refer Applet documentation.


Call details

To get details of a call (including Status, Price, etc.), you will need to make a HTTP GET request to

GET

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/<CallSid>

Where <CallSid> is an alpha-numeric unique identifier generated for all the calls made via Exotel.

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

In the case of an outbound call originated via the API, the Sid parameter is as returned in the XML/JSON response to your request. In the case of inbound calls, you can get the Sid by using the Passthru applet.

curl https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/b6cfaf5f5cef3ca0fc937749ef960e25 
            
var request = require('request');

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/b6cfaf5f5cef3ca0fc937749ef960e25'
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/b6cfaf5f5cef3ca0fc937749ef960e25', $headers);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/b6cfaf5f5cef3ca0fc937749ef960e25")
response = Net::HTTP.get_response(uri)

# response.code
# response.body
            
import requests

requests.get('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/b6cfaf5f5cef3ca0fc937749ef960e25')
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
 <Call>
  <Sid>b6cfaf5f5cef3ca0fc937749ef960e25</Sid>
  <ParentCallSid></ParentCallSid>
  <DateCreated>2017-02-17 14:16:03</DateCreated>
  <DateUpdated>2017-02-17 14:17:32</DateUpdated>
  <AccountSid>Exotel</AccountSid>
  <To>0XXXXX20000</To>
  <From>0XXXXX30240</From>
  <PhoneNumberSid>0XXXXXX4890</PhoneNumberSid>
  <Status>completed</Status>
  <StartTime>2017-02-17 14:16:03</StartTime>
  <EndTime>2017-02-17 14:16:20</EndTime>
  <Duration>17</Duration>
  <Price>0.750</Price>
  <Direction>inbound</Direction>
  <AnsweredBy>human</AnsweredBy>
  <ForwardedFrom></ForwardedFrom>
  <CallerName></CallerName>
  <Uri>/v1/Accounts/<your_sid>/Calls/b6cfaf5f5cef3ca0fc937749ef960e25</Uri>
  <RecordingUrl>https://s3-ap-southeast-1.amazonaws.com/exotelrecordings/<your_sid>/b6cfaf5f5cef3ca0fc937749ef960e25.mp3</RecordingUrl>
 </Call>
</TwilioResponse>
            
{
  "Call": {
    "Sid": "b6cfaf5f5cef3ca0fc937749ef960e25",
    "ParentCallSid": "",
    "DateCreated": "2016-11-29 15:58:45",
    "DateUpdated": "2016-11-29 16:00:09",
    "AccountSid": "Exotel",
    "To": "0XXXXX20000",
    "From": "0XXXXX30240",
    "PhoneNumberSid": "0XXXXXX4890",
    "Status": "completed",
    "StartTime": "2016-11-29 15:59:10",
    "EndTime": "2016-11-29 15:59:27",
    "Duration": "17",
    "Price": "1.500",
    "Direction": "outbound-api",
    "AnsweredBy": "human",
    "ForwardedFrom": "",
    "CallerName": "",
    "Uri": "/v1/Accounts/<your_sid>/Calls/b6cfaf5f5cef3ca0fc937749ef960e25",
    "RecordingUrl": "https://s3-ap-southeast-1.amazonaws.com/exotelrecordings/<your_sid>/b6cfaf5f5cef3ca0fc937749ef960e25.mp3"
  }
}

            

Description of parameters mentioned in the above response:

Parameter NameType & Value
Sidstring; an alpha-numeric unique identifier of the call
DateCreatedDate and time at which the user initiated the API
DateUpdatedDate and time at which the status of the call was last updated in our system
AccountSidYour account SID
ToYour customer's phone number
FromThe phone number that will be called first
PhoneNumberSidThis is your ExoPhone/Exotel Virtual Number
StatusWhen the call completes, an HTTP POST will be made to the URL mentioned with the following four parameters:
  • queued - The call is ready and waiting in line before going out
  • in-progress - The call was answered and is currently in progress
  • completed - The call was answered and has ended normally
  • failed - The call could not be completed as dialled, most likely because the phone number was non-existent
  • busy - The caller received a busy signal
  • no-answer - The call ended without being answered
StartTimeTime in format YYYY-MM-DD HH:mm:ss; Date and time when the call request was initiated to the operator
EndTimeTime in format YYYY-MM-DD HH:mm:ss; Date and time when the call was completed
DurationCall duration in seconds
PriceDouble; If present, this will be the amount (in INR or USD) you have been charged for the call
Direction
  • inbound
  • outbound-dial - Outbound calls from Exotel dashboard
  • outbound-api - All other Outbound calls (API, campaign etc.)
AnsweredByhuman
UriUri is the path of the CallSid
RecordingUrlLink to the call recording

If status of both the call legs are required incase of an outbound call, you will need to make an HTTP GET request to

GET

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Calls/<CallSid>?details=true

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
    <Call>
        <Sid>b6cfaf5f5cef3ca0fc937749ef96d245</Sid>
        <ParentCallSid></ParentCallSid>
        <DateCreated>2016-11-29 15:58:45</DateCreated>
        <DateUpdated>2016-11-29 16:00:09</DateUpdated>
        <AccountSid>Exotel</AccountSid>
        <To>0XXXXX30240</To>
        <From>0XXXXX85175</From>
        <PhoneNumberSid>0XXXXXX4890</PhoneNumberSid>
        <Status>completed</Status>
        <StartTime>2016-11-29 15:59:10</StartTime>
        <EndTime>2016-11-29 15:59:27</EndTime>
        <Duration>17</Duration>
        <Price>1.500</Price>
        <Direction>outbound-api</Direction>
        <AnsweredBy>human</AnsweredBy>
        <ForwardedFrom></ForwardedFrom>
        <CallerName></CallerName>
        <Uri>/v1/Accounts/Exotel/Calls/b6cfaf5f5cef3ca0fc937749ef96d245</Uri>
        <RecordingUrl>https://s3-ap-southeast-1.amazonaws.com/exotelrecordings/Exotel/b6cfaf5f5cef3ca0fc937749ef96d245.mp3</RecordingUrl>
        <Details>
            <ConversationDuration>8</ConversationDuration>
            <Leg1Status>completed</Leg1Status>
            <Leg2Status>completed</Leg2Status>
            <Legs>
                <Leg>
                    <Id>1</Id>
                    <OnCallDuration>21</OnCallDuration>
                </Leg>
                <Leg>
                    <Id>2</Id>
                    <OnCallDuration>8</OnCallDuration>
                </Leg>
            </Legs>
        </Details>
    </Call>
</TwilioResponse>
            
{
  "Call": {
    "Sid": "b6cfaf5f5cef3ca0fc937749ef96d245",
    "ParentCallSid": "",
    "DateCreated": "2016-11-29 15:58:45",
    "DateUpdated": "2016-11-29 16:00:09",
    "AccountSid": "Exotel",
    "To": "0XXXXX30240",
    "From": "0XXXXX85175",
    "PhoneNumberSid": "0XXXXXX4890",
    "Status": "completed",
    "StartTime": "2016-11-29 15:59:10",
    "EndTime": "2016-11-29 15:59:27",
    "Duration": "17",
    "Price": "1.500",
    "Direction": "outbound-api",
    "AnsweredBy": "human",
    "ForwardedFrom": "",
    "CallerName": "",
    "Uri": "/v1/Accounts/Exotel/Calls/b6cfaf5f5cef3ca0fc937749ef96d245",
    "RecordingUrl": "https://s3-ap-southeast-1.amazonaws.com/exotelrecordings/Exotel/b6cfaf5f5cef3ca0fc937749ef96d245.mp3",
    "Details": {
      "ConversationDuration": 8,
      "Leg1Status": "completed",
      "Leg2Status": "completed"
      "Legs": [
        "Leg": {
          "Id": "1",
          "OnCallDuration": 21,
        },
        "Leg": {
          "Id": "2",
          "OnCallDuration": 8,
        }
      ]
    }
  }
}


            

Description of parameters mentioned in the above response:

Parameter NameValue
ConversationDurationThe duration for the From and To phone numbers on call in seconds
Leg1StatusStatus of the first leg of the call. Can be one of
  • queued - The call is ready and waiting in line before going out
  • ringing - The call is currently ringing
  • in-progress - The call was answered and is currently in progress
  • completed - The call was answered and has ended normally
  • busy - The caller received a busy signal
  • failed - The call could not be completed as dialled, most likely because the phone number was non-existent
  • no-answer - The call ended without being answered
  • canceled - The call was canceled while queued or ringing
Leg2StatusStatus of the second leg of the call. Can be one of
  • completed - The call was answered and has ended normally
  • busy - The caller received a busy signal
  • no-answer - The call ended without being answered
  • failed - The call could not be completed as dialed, most likely because the phone number was non-existent
  • canceled - The call was canceled while queued or ringing
  • null (empty) - The call did not have a second leg
LegsStatus of individual legs of the call. Contains the following information (per leg):
  • Id - Indicates the leg. Can be 1 or 2.
  • OnCallDuration - Indicates the duration that this leg was on a call (see below for more information on how this is calculated).

The following diagram illustrates how the call duration is calculated for a call and its constituent legs.

Call recording duration calculation

Whitelist

Whitelist API allows you to add your DND clients' phone numbers into the Exotel's system and hence allowing you to call them. Exotel maintains the list of phone numbers subscribed to TRAI regulated DND (Do Not Disturb) / NCPR (National Customer Preference Registry). In general, a phone number subscribed to DND should not be dialed for marketing/commercial calls. Exotel differentiates these as transactional calls and promotional calls.

This is how it works:

  • You use the Customer whitelist API and add your DND customers' numbers into the Whitelist
  • An SMS is automatically sent to these numbers asking them their permission for you to contact them. Sample SMS: You've registered with <Your-company-Name> and permitted us to call you. If this is not the case, please give a missed call to 09XXXXXXXX. Thank you!
  • You can choose the brand name that goes in the opt-in SMS (<Your-company-Name> in the above Sample SMS). You can edit this in the "Brand Name" field in the company info page
  • If the person does not want to receive calls from you, s/he can 'unsubscribe' by giving a missed call to a specified number (in a SMS). Following this you will not be able to call him/her.
  • Once you have 'whitelisted' a DND number, you can make outbound transactional calls to that number

Important: If more than 3 people 'unsubscribe', then the process for whitelisting will change. Now, instead of getting a number that is on DND to 'unsubscribe' by giving a missed call, for you to be able to call him/her, the number will have to 'subscribe' by giving a missed call. Steps 3,4 will change accordingly. The following steps will then take place:

  • Sample SMS: You've registered with <Your-company-name>. As you're on DND, please authorise us to call you by giving a missed call to 09XXXXXXXXX
  • If the person wants to receive calls from you, they would have to give a missed call on the given number. Until that, you would be unable to contact that number
  • This is done to ensure that this whitelist API is used genuinely and only for transactional calls
  • The above mentioned SMSes are sent from your registered sender ID and the cost of the SMS will be deducted from your account

To start with, a list of DND numbers, who you wish to contact, needs to be prepared. While posting these numbers to Exotel, a Virtual Number/ExoPhone need to be specified using which SMSes can be sent to the DND numbers. On posting to Exotel, a SMS is sent to the DND number informing them that a company has added them as a client and an option is given to accept or deny calls from the company.

Adding to the whitelist

To add a list of DND numbers through our API, you will need to make a HTTP POST request to

POST

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

The following are the POST parameters:

Parameter NameMandatory/OptionalValue
VirtualNumberMandatoryThis is your ExoPhone/Virtual Number (pick one from here)
NumberMandatoryList of phone numbers to be added in the whitelist.
LanguageOptionalThe Language parameter specifies the language in which the SMS should be sent to the user. The following languages are supported.
  • en - English
  • ta - Tamil
The default Language is English (en).
 curl -X POST https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/ \
 -d "VirtualNumber=XXXXX30240" \
 -d "Number=XXXXX40682" \
 -d "Language=en"
            
var request = require('request');

var dataString = 'VirtualNumber=XXXXX30240&Number=XXXXX40682&Language=en';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/',
    method: 'POST',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'VirtualNumber' => 'XXXXX30240',
    'Number' => 'XXXXX40682',
    'Language' => 'en'
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist")
request = Net::HTTP::Post.new(uri)
request.set_form_data(
  "VirtualNumber" => "XXXXX30240",
  "Number" => "XXXXX40682",
  "Language" => "en",
)

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = {
  'VirtualNumber': 'XXXXX30240',
  'Number': 'XXXXX40682',
  'Language': 'en'
}

requests.post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an XML/JSON similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
<Result>
<Total>2</Total>
<Duplicate>0</Duplicate>
<Processed>2</Processed>
<Succeeded>2</Succeeded>
<Redundant>0</Redundant>
<Failed>0</Failed>
<Message>The numbers have been added to the whitelist. If DND number gives a missed call to unsubscribe, the corresponding number will be removed from whitelist.</Message>
</Result>
</TwilioResponse>
            

Description of parameters mentioned in the above response:

Parameter NameType & Value
Result/TotalTotal numbers provided
Result/DuplicateCount of duplicate numbers skipped
Result/ProcessedCount of processed numbers
Result/SucceededCount of successfully processed numbers
Result/RedundantCount of number with no action taken
Result/FailedCount of failed numbers
MessageDescription of the action in plain text. The text 'The numbers have been added to the whitelist' would be present in the message only when Result/Succeeded > 0

Deleting from the whitelist

To delete a list of whitelisted numbers through our API, you will need to make a HTTP DELETE request to

DELETE

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist?Number=94870XXXX,97902XXXX

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

 curl -X DELETE https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist?Number=94870XXXX,97902XXXX
            
var request = require('request');

var dataString = 'VirtualNumber=XXXXX30240&Number=XXXXX40682&Language=en';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist?Number=94870XXXX,97902XXXX',
    method: 'DELETE',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'VirtualNumber' => 'XXXXX30240',
    'Number' => 'XXXXX40682',
    'Language' => 'en'
);
$response = Requests::delete('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist?Number=94870XXXX,97902XXXX', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist?Number=94870XXXX,97902XXXX")
request = Net::HTTP::Delete.new(uri)
request.set_form_data(
  "VirtualNumber" => "XXXXX30240",
  "Number" => "XXXXX40682",
  "Language" => "en",
)

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = {
  'VirtualNumber': 'XXXXX30240',
  'Number': 'XXXXX40682',
  'Language': 'en'
}

requests.delete('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist?Number=94870XXXX,97902XXXX', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an XML/JSON similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
<Result>
<Total>2</Total>
<Duplicate>0</Duplicate>
<Processed>2</Processed>
<Succeeded>2</Succeeded>
<Redundant>0</Redundant>
<Failed>0</Failed>
<Message>The numbers have been deleted from the whitelist.</Message>
</Result>
</TwilioResponse>
            

Description of parameters mentioned in the above response:

Parameter NameType & Value
Result/TotalTotal numbers provided
Result/DuplicateCount of duplicate numbers skipped
Result/ProcessedCount of processed numbers
Result/SucceededCount of successfully processed numbers
Result/RedundantCount of number with no action taken
Result/FailedCount of failed numbers

Whitelist details

Exotel allows you to make outbound calls to DND numbers which have been whitelisted. To check if a number has been whitelisted or not, you will need to make a HTTP GET request to

GET

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/<number>

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

curl https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/XXXXX30240
            
var request = require('request');

var dataString = 'From=XXXXX30240&To=9415540682&CallerId=0XXXXXX4890';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/XXXXX30240',
    method: 'POST',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'From' => 'XXXXX30240',
    'To' => '9415540682',
    'CallerId' => '0XXXXXX4890'
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/XXXXX30240', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/XXXXX30240")
request = Net::HTTP::Post.new(uri)
request.set_form_data(
  "From" => "XXXXX30240",
  "To" => "9415540682",
  "CallerId" => "0XXXXXX4890",
)

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = {
  'From': 'XXXXX30240',
  'To': '9415540682',
  'CallerId': '0XXXXXX4890'
}

requests.post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/CustomerWhitelist/XXXXX30240', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an XML/JSON similar to the one below
<Result>
    <Status>(Whitelist|Blacklist|Neutral)</Status>
    <Type>(Customer|Agent|API|<empty>)</Type>
    <Expiry>(-1|<seconds>)</Expiry>
</Result>
            

Description of parameters mentioned in the above response:

Parameter NameType & Value
Result/Status
  • Whitelist - The number has been whitelisted. You can make outbound calls to this number.
  • Blacklist - The number has been blacklisted. The number has explicitly unsubscribed from getting your calls.
  • Neutral - You cannot make outbound calls to this number.
Result/Type
  • Customer - The customer had made an inbound call to your ExoPhone and has automatically been whitelisted.
  • Agent - This number belongs to your co-worker (Exotel user). All co-workers numbers are automatically whitelisted.
  • API - You have used the customer whitelisting API to whitelist this number.
Result/ExpiryContains the number of seconds after which the number will not be in this state (typically whitelist).
  • -1 - There is no expiry. The number remains in this state forever.

Number metadata

This API provides the following metadata about a phone number:

  • Telecom Circle
  • Telecom Circle Name
  • Number Type
  • Whether the number belongs to DND or not

To get the above information you need to make a HTTP GET request to

GEThttps://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Numbers/~number~

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

curl https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Numbers/XXXXX30240 
            
var request = require('request');

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Numbers/XXXXX30240'
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Numbers/XXXXX30240', $headers);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Numbers/XXXXX30240")
response = Net::HTTP.get_response(uri)

# response.code
# response.body
            
import requests

requests.get('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Numbers/XXXXX30240')
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
 <Numbers>
  <PhoneNumber>0XXXXX30240</PhoneNumber>
  <Circle>GJ</Circle>
  <CircleName>Gujarat Telecom Circle (includes Daman &amp; Diu, Dadra &amp; Nagar Haveli)</CircleName>
  <Type>Mobile</Type>
  <Operator>R</Operator>
  <OperatorName>Reliance</OperatorName>
  <DND>Yes</DND>
 </Numbers>
</TwilioResponse>
            
{
  "Numbers": {
    "PhoneNumber": "0XXXXX30240",
    "Circle": "GJ",
    "CircleName": "Gujarat Telecom Circle (includes Daman & Diu, Dadra & Nagar Haveli)",
    "Type": "Mobile",
    "Operator": "R",
    "OperatorName": "Reliance",
    "DND": "Yes"
  }
}


Description of parameters mentioned in the above response:

Parameter NameType & Value
PhoneNumberstring; Reformatted phone number
CircleTwo character telecom circle code. Refer below table for more details
CircleNameHuman readable string of the Circle code. Ex: Haryana Telecom Circle (excludes Faridabad, Gurgaon & Panchkula)
Type'Mobile' or 'Landline'
OperatorSingle or two character telecom operator code. Refer below table for more details
OperatorNameTelecom operator to which the number belongs
DND
  • Yes
  • No
  • Unavailable

Description of all the telecom circles in India:

Circle NameValue
APAndhra Pradesh Telecom Circle
ASAssam Telecom Circle
BRBihar & Jharkhand Telecom Circle
CHChennai Metro Telecom Circle (includes Chennai, MEPZ & Mahabalipuram)
DLDelhi Metro Telecom Circle (includes NCR, Faridabad, Ghaziabad, Gurgaon & Noida)
GJGujarat Telecom Circle (includes Daman & Diu, Dadra & Nagar Haveli)
HPHimachal Pradesh Telecom Circle
HRHaryana Telecom Circle (excludes Faridabad, Gurgaon & Panchkula)
JKJammu & Kashmir Telecom Circle
KLKerala Telecom Circle (includes Lakshadeep)
KAKarnataka Telecom Circle
KOKolkata Metro Telecom Circle (includes parts of Haora, Hooghly, North & South 24 Parganas and Nadia Districts)
MHMaharashtra Telecom Circle (includes Goa but excludes Mumbai, Navi Mumbai & Kalyan)
MPMadhya Pradesh & Chhattisgarh Telecom Circle
MUMumbai Metro Telecom Circle (includes Navi Mumbai & Kalyan)
NENorth East India Telecom Circle (includes Arunachal Pradesh, Meghalaya, Mizoram, Nagaland, Manipur & Tripura)
OROrissa Telecom Circle
PBPunjab Telecom Circle (includes Chandigarh & Panchkula)
RJRajasthan Telecom Circle
TNTamil Nadu Telecom Circle (excludes CH Chennai, MEPZ, Mahabalipuram & Minjur and includes Pondicherry except Yanam & Mahe)
UEUttar Pradesh (East) Telecom Circle
UWUttar Pradesh (West) & Uttarakhand Telecom Circle (excludes Ghaziabad & Noida)
WBWest Bengal Telecom Circle (includes Andaman & Nicobar,Sikkim excludes Calcutta Telecom District)
ANAndaman & Nicobar
BYMumbai Metro Telecom Circle (includes Navi Mumbai & Kalyan)
HAHaryana Telecom Circle (excludes Faridabad, Gurgaon & Panchkula)
NDDelhi Metro Telecom Circle (includes NCR, Faridabad, Ghaziabad, Gurgaon & Noida)
UPEUttar Pradesh (East) Telecom Circle
UPWUttar Pradesh (West) & Uttarakhand Telecom Circle (excludes Ghaziabad & Noida)

Description of Telecom operators in India:

Operator NameValue
ACAircel
AAirtel
ALAllianz
BBSNL
DDishnet
EEtisalat
HHFCL
IIdea
LOLoop
MTMTNL
PPing
RReliance
SSistema
STS Tel
TTata
UUnitech
VIVideocon
VVodafone

Send SMS

This API will send an SMS to the specified To number. To send an SMS through our API, you will need to make a HTTP POST request to

POST

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

The following are the POST parameters:

Parameter NameMandatory/OptionalValue
FromMandatory
  • Specify one of your ExoPhone
  • For transactional SMSes, the SenderID (When you buy an ExoPhone, you will be asked to enter a 6-letter sender ID from which your SMSes will be sent. For Eg: LM-EXOTEL or LM-WEBDEV etc.) will be the one that corresponds to the ExoPhone
  • For promotional SMSes, the SenderID will anyways be a generic numeric one (Ex: LM-123456)
ToMandatoryMobile number to which SMS has to be sent. Preferably in E.164 format. If not set, our system will try to match it with a country and route the SMS
BodyMandatoryContent of your SMS; Max Length of the body cannot exceed 2000 characters
EncodingTypeOptionalMessage type of SMS; plain or unicode
PriorityOptionalPriority of the SMS; normal or high. Business critical operations like sending verification codes, confirming appointments etc which require immediate SMS delivery should opt for high priority.
StatusCallbackOptionalOnce SMS reaches terminal state (sent/failed/failed-dnd), Exotel will do a POST callback to your end point if the URL is set as a parameter in the API. Content-type for the POST callback is application/x-www-form-urlencoded Below are the parameters:
  • SmsSid - The Sid (unique id) of the SMS that you got in response to your request
  • To - Mobile number to which SMS was sent
  • Status - one of: queued, sending, submitted, sent, failed-dnd, failed
curl -X POST https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send \
-d "From=0XXXXXX4890" \
-d "To=XXXXX30240" \
-d "Body=Hello World!"
            
var request = require('request');

var dataString = 'From=0XXXXXX4890&To=XXXXX30240&Body=Hello World!';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send',
    method: 'POST',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'From' => '0XXXXXX4890',
    'To' => 'XXXXX30240',
    'Body' => 'Hello World!'
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send")
request = Net::HTTP::Post.new(uri)
request.body = "From=0XXXXXX4890&To=XXXXX30240&Body=Hello World!"

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = {
  'From': '0XXXXXX4890',
  'To': 'XXXXX30240',
  'Body': 'Hello World!'
}

requests.post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The Sid is the unique identifier of the SMS and it will be useful to log this for future debugging
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
 <SMSMessage>
  <Sid>0b6c6a98f32682862ce6edf1bdab3526</Sid>
  <AccountSid>Exotel</AccountSid>
  <From>0XXXXXX4890/WEBDEV</From>
  <To>XXXXX30240</To>
  <DateCreated>2017-02-22 07:01:24</DateCreated>
  <DateUpdated>2017-02-22 07:01:24</DateUpdated>
  <DateSent/>
  <Body>Hello World!</Body>
  <Direction>outbound-api</Direction>
  <Uri>/v1/Accounts/Exotel/Sms/Messages/0b6c6a98f32682862ce6edf1bdab3526</Uri>
  <ApiVersion/>
  <Price/>
  <Status>queued</Status>
  <DetailedStatusCode>21010</DetailedStatusCode>
  <DetailedStatus>PENDING_TO_OPERATOR</DetailedStatus>
 </SMSMessage>
</TwilioResponse>
            
{
  "SMSMessage": {
    "Sid": "0f477d60517e6e6a0f6d9a7e9af8630e",
    "AccountSid": "Exotel",
    "From": "0XXXXXX4890/WEBDEV",
    "To": "0XXXXX30240",
    "DateCreated": "2017-03-03 14:14:20",
    "DateUpdated": "2017-03-03 14:14:20",
    "DateSent": null,
    "Body": "Hello World!",
    "Direction": "outbound-api",
    "Uri": "/v1/Accounts/Exotel/Sms/Messages.json/0f477d60517e6e6a0f6d9a7e9af8630e",
    "ApiVersion": null,
    "Price": null,
    "Status": "queued"
    "DetailedStatusCode": "21010"
    "DetailedStatus": "PENDING_TO_OPERATOR"    
  }
}

Description of parameters mentioned in the above response:

Parameter NameType & Value
Sidstring; an alpha-numeric unique identifier of the SMS
AccountSidString; Your account identifier
FromString; It is of format <VN>/<SenderID> where <VN> is your Exotel Virtual Number/ExoPhone through which you are sending the SMS. <SenderID> is the SenderID via which this SMS was sent
ToString; The mobile number(s) to which the SMS was sent
DateCreatedTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was received at our server
DateUpdatedTime in format YYYY-MM-DD HH:mm:ss; The time when any property of this SMS was last updated by our server
DateSentTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was delivered to the recepient
BodyString; The body of the SMS message sent
StatusCan be of:
  • queued - This means that the SMS you have sent has been queued internally for delivery
  • sending - This means that we're in process of sending the SMS to upstream provider/gateway
  • submitted - This means that the SMS you have sent has been submitted from our system to SMS Gateway
  • sent - The SMS was successfully delivered to the handset
  • failed-dnd - The delivery of the SMS failed because the number belongs to the TRAI NCPR list. This is applicable only for promotional SMS
  • failed - The delivery of SMS failed. Please see DetailedStatusCode and DetailedStatus for further details.
DetailedStatusHuman readable word that explains what happened to the Message. Log these strings in your log files for grepping and debugging by a developer.
DetailedStatusCodeExotel’s Detailed Status code corresponding to the DetailedStatus. Use this field to build decision making in your code.
PriceDouble; If present, this will be the amount (in INR or USD) you have been charged for the SMS
Direction
  • incoming - incoming messages
  • outbound-api - messages initiated via the REST API
  • outbound-call - messages initiated during a call
  • outbound-reply - messages initiated in response to an incoming message
UriUri is the path of the SmsSid

Mapping and Description of status codes

Detailed Status CodeNature of Detailed Status CodeStatusDetailedStatusWhat it means
21010Intermediate, may change in futurequeuedPENDING_TO_OPERATORThe message is is being processed by Exotel.
21015Intermediate, may change in futuresendingSENDING_TO_OPERATORThe message has been processed by Exotel and is en-route to the operator.
21020Intermediate, may change in futuresubmittedPENDING_ON_OPERATORThe message has been successfully Submitted to the operator and is pending delivery. In India, Promotional SMS may be in this state if submitted outside permitted time (9AM to 9PM).
20005FinalsentDELIVERED_TO_HANDSETWe know with confidence that the message has been delivered to recipient's handset.
20006FinalsentDELIVERED_TO_OPERATORThe message has been delivered to operator. In some regions and routes, handset delivery status (DELIVERED_TO_HANDSET) is not available and hence this is the best we can ever report about the delivery status.
23005Finalfailed-dndFAILED_REJECTED_DNDThe message has been rejected as the end user is a subscriber of DND (Do Not Disturb) services.
23010FinalfailedFAILED_INVALID_DESTINATION_NUMBERThe destination number is incorrect, not SMS-enabled or is a PSTN landline.
23015FinalfailedFAILED_SPAM_DETECTEDOne of the most common reasons for SMS delivery failure is carrier level spam filters. Carriers have added systems and algorithms that detect spam content and then block these messages. Unfortunately, these filters are hidden, subject to carrier preferences, vary from carrier to carrier, and can be changed without notice.
23020FinalfailedFAILED_REJECTED_BLACKLISTYou tried to send a message to a blacklisted phone number. That is, the user has already sent a STOP/DND opt-out message and no longer wishes to receive messages from you.
24990FinalfailedFAILED_UNKNOWN_ERRORDelivering your message failed for reasons that are unknown to us and to our carriers. If you notice too many of these cases, please reach out to us.
23030FinalfailedFAILED_UNAVAILABLE_ROUTEThe carrier and fallback carriers were not able to deliver the SMS message because no route was available.
23035FinalfailedFAILED_SUBSCRIBER_UNAVAILABLEThis message was not delivered because subscriber was temporarily unavailable. For example, the receiving handset was out of coverage or switched off. This is a temporary failure, but a message sent to the same subscriber at a later point in time may get delivered.
23040FinalfailedFAILED_SUBSCRIBER_UNKNOWNSubscriber is unknown to the operators or no longer active.
23050FinalfailedFAILED_EXPIREDThe message was sent to the operator and may have been retried several times within the default network SMS expiration duration. The message request has now expired.
23060FinalfailedFAILED_REJECTEDFor a number of reasons, the message was rejected by Exotel or the operator.
24105FinalfailedFAILED_HANDSET_ERRORThe message was not delivered to the subscriber due to handset failure
24110FinalfailedFAILED_OPERATOR_ERRORThe message failed due to an issue at the operator end
23070FinalfailedFAILED_INVALID_MESSAGEThe message was rejected by the operator as Invalid. While Exotel will automatically split messages longer than 160 GSM 7-bit characters, or 70 unicode 16-bit characters into multipart SMS, Messages exceeding the allowed character limit of 2000 characters may also end in this state. Any request error related to the message, say unindentified character, may also fall under this bucket.
24010FinalfailedFAILED_SYSTEM_ERRORSMS failed while processing within Exotel system.
24120FinalfailedFAILED_SUBSCRIBER_ERRORAll subscriber or recipeient issues that are unrelated to the handset (For ex - Receiver does not have enough mobile balance to receive the SMS) may fall under this bucket.

SMS details

To get the details of a SMS (including Status, Direction, etc.), you will need to make a HTTP GET request to

GET

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/SMS/Messages/<SmsSid>

where <SmsSid> is the Sid of the SMS.

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

curl https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/SMS/Messages/0b6c6a98f32682862ce6edf1bdab3526
            
var request = require('request');

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/SMS/Messages/0b6c6a98f32682862ce6edf1bdab3526'
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/SMS/Messages/0b6c6a98f32682862ce6edf1bdab3526', $headers);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/SMS/Messages/0b6c6a98f32682862ce6edf1bdab3526")
response = Net::HTTP.get_response(uri)

# response.code
# response.body
            
import requests

requests.get('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/SMS/Messages/0b6c6a98f32682862ce6edf1bdab3526')
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
 <SMSMessage>
  <Sid>0b6c6a98f32682862ce6edf1bdab3526</Sid>
  <AccountSid>Exotel</AccountSid>
  <From>0XXXXXX4890/WEBDEV</From>
  <To>XXXXX30240</To>
  <DateCreated>2017-02-22 07:01:24</DateCreated>
  <DateUpdated>2017-02-22 07:01:28</DateUpdated>
  <DateSent>1970-01-01 05:30:00</DateSent>
  <Body>Hello World!</Body>
  <Direction>outbound-api</Direction>
  <Uri>/v1/Accounts/Exotel/Sms/Messages/0b6c6a98f32682862ce6edf1bdab3526</Uri>
  <ApiVersion/>
  <Price/>
  <Status>submitted</Status>
  <DetailedStatusCode>21020</DetailedStatusCode>
  <DetailedStatus>PENDING_ON_OPERATOR</DetailedStatus>
 </SMSMessage>
</TwilioResponse>
            
{
  "SMSMessage": {
    "Sid": "0f477d60517e6e6a0f6d9a7e9af8630e",
    "AccountSid": "Exotel",
    "From": "0XXXXXX4890/WEBDEV",
    "To": "0XXXXX30240",
    "DateCreated": "2017-03-03 14:14:20",
    "DateUpdated": "2017-03-03 14:14:20",
    "DateSent": null,
    "Body": "Hello World!",
    "Direction": "outbound-api",
    "Uri": "/v1/Accounts/Exotel/Sms/Messages.json/0f477d60517e6e6a0f6d9a7e9af8630e",
    "ApiVersion": null,
    "Price": null,
    "Status": "queued"
    "DetailedStatusCode": "21020"
    "DetailedStatus": "PENDING_ON_OPERATOR"    
  }
}

          

Description of parameters mentioned in the above response:

Parameter NameType & Value
Sidstring; an alpha-numeric unique identifier of the SMS
AccountSidString; Your account identifier
FromString; It is of format <VN>/<SenderID> where <VN> is your Exotel Virtual Number/ExoPhone through which you are sending the SMS. <SenderID> is the SenderID via which this SMS was sent
ToString; Mobile number to which SMS was sent. Preferably in E.164 format. If not set, our system will try to match it with a country and route the SMS
DateCreatedTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was received at our server
DateUpdatedTime in format YYYY-MM-DD HH:mm:ss; The time when any property of this SMS was last updated by our server
DateSentTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was delivered to the recepient
BodyString; The body of the SMS message sent
StatusCan be of:
  • queued - This means that the SMS you have sent has been queued internally for delivery
  • sending - This means that we're in process of sending the SMS to upstream provider/gateway
  • submitted - This means that the SMS you have sent has been submitted from our system to SMS Gateway
  • sent - The SMS was successfully delivered to the handset
  • failed-dnd - The delivery of the SMS failed because the number belongs to the TRAI NCPR list. This is applicable only for promotional SMS
  • failed - The delivery of SMS failed. Please see DetailedStatusCode and DetailedStatus for further details.
DetailedStatusHuman readable word that explains what happened to the Message. Log these strings in your log files for grepping and debugging by a developer.
DetailedStatusCodeExotel’s Detailed Status code corresponding to the DetailedStatus. Use this field to build decision making in your code.
PriceDouble; If present, this will be the amount (in INR) you have been charged for the SMS
Direction
  • incoming - incoming messages
  • outbound-api - messages initiated via the REST API
  • outbound-call - messages initiated during a call
  • outbound-reply - messages initiated in response to an incoming message
UriUri is the path of the SmsSid

Mapping and Description of status codes:

Detailed Status CodeNature of Detailed Status CodeStatusDetailedStatusWhat it means
21010Intermediate, may change in futurequeuedPENDING_TO_OPERATORThe message is is being processed by Exotel.
21015Intermediate, may change in futuresendingSENDING_TO_OPERATORThe message has been processed by Exotel and is en-route to the operator.
21020Intermediate, may change in futuresubmittedPENDING_ON_OPERATORThe message has been successfully Submitted to the operator and is pending delivery. In India, Promotional SMS may be in this state if submitted outside permitted time (9AM to 9PM).
20005FinalsentDELIVERED_TO_HANDSETWe know with confidence that the message has been delivered to recipient's handset.
20006FinalsentDELIVERED_TO_OPERATORThe message has been delivered to operator. In some regions and routes, handset delivery status (DELIVERED_TO_HANDSET) is not available and hence this is the best we can ever report about the delivery status.
23005Finalfailed-dndFAILED_REJECTED_DNDThe message has been rejected as the end user is a subscriber of DND (Do Not Disturb) services.
23010FinalfailedFAILED_INVALID_DESTINATION_NUMBERThe destination number is incorrect, not SMS-enabled or is a PSTN landline.
23015FinalfailedFAILED_SPAM_DETECTEDOne of the most common reasons for SMS delivery failure is carrier level spam filters. Carriers have added systems and algorithms that detect spam content and then block these messages. Unfortunately, these filters are hidden, subject to carrier preferences, vary from carrier to carrier, and can be changed without notice.
23020FinalfailedFAILED_REJECTED_BLACKLISTYou tried to send a message to a blacklisted phone number. That is, the user has already sent a STOP/DND opt-out message and no longer wishes to receive messages from you.
24990FinalfailedFAILED_UNKNOWN_ERRORDelivering your message failed for reasons that are unknown to us and to our carriers. If you notice too many of these cases, please reach out to us.
23030FinalfailedFAILED_UNAVAILABLE_ROUTEThe carrier and fallback carriers were not able to deliver the SMS message because no route was available.
23035FinalfailedFAILED_SUBSCRIBER_UNAVAILABLEThis message was not delivered because subscriber was temporarily unavailable. For example, the receiving handset was out of coverage or switched off. This is a temporary failure, but a message sent to the same subscriber at a later point in time may get delivered.
23040FinalfailedFAILED_SUBSCRIBER_UNKNOWNSubscriber is unknown to the operators or no longer active.
23050FinalfailedFAILED_EXPIREDThe message was sent to the operator and may have been retried several times within the default network SMS expiration duration. The message request has now expired.
23060FinalfailedFAILED_REJECTEDFor a number of reasons, the message was rejected by Exotel or the operator.
24105FinalfailedFAILED_HANDSET_ERRORThe message was not delivered to the subscriber due to handset failure
24110FinalfailedFAILED_OPERATOR_ERRORThe message failed due to an issue at the operator end
23070FinalfailedFAILED_INVALID_MESSAGEThe message was rejected by the operator as Invalid. While Exotel will automatically split messages longer than 160 GSM 7-bit characters, or 70 unicode 16-bit characters into multipart SMS, Messages exceeding the allowed character limit of 2000 characters may also end in this state. Any request error related to the message, say unindentified character, may also fall under this bucket.
24010FinalfailedFAILED_SYSTEM_ERRORSMS failed while processing within Exotel system.
24120FinalfailedFAILED_SUBSCRIBER_ERRORAll subscriber or recipeient issues that are unrelated to the handset (For ex - Receiver does not have enough mobile balance to receive the SMS) may fall under this bucket.

Exotel can push the SMS status to you after the SMS reaches any terminal state ie sent, failed or failed-dnd. For this, you need to pass an additional parameter StatusCallback along with your other parameters. This parameter should be an URL hosted by you.

Exotel will make a POST request to the StatusCallback with the following parameter:

  • SmsSid - The Sid (unique id) of the SMS that you got in response to your request
  • To - Mobile number to which SMS was sent
  • Status - one of: queued, sending, submitted, sent, failed-dnd, failed

Send Bulk SMS With Static Content

This API will send SMSes with the same content to the array of numbers specified in the To parameter. To send SMS through our API, you will need to make a HTTP POST request to

POST

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

The following are the POST parameters:

Parameter NameMandatory/OptionalValue
FromMandatory
  • Specify one of your ExoPhone
  • For transactional SMSes, the SenderID (When you buy an ExoPhone, you will be asked to enter a 6-letter sender ID from which your SMSes will be sent. For Eg: LM-EXOTEL or LM-WEBDEV etc.) will be the one that corresponds to the ExoPhone
  • For promotional SMSes, the SenderID will anyways be a generic numeric one (Ex: LM-123456)
ToMandatoryArray of Mobile numbers to which SMS has to be sent. Preferably in E.164 format. If not set, our system will try to match it with a country and route the SMS
BodyMandatoryContent of your SMS; Max Length of the body cannot exceed 2000 characters
EncodingTypeOptionalMessage type of SMS; plain or unicode
PriorityOptionalPriority of the SMS; normal or high. Business critical operations like sending verification codes, confirming appointments etc which require immediate SMS delivery should opt for high priority.
StatusCallbackOptionalAfter every SMS reaches terminal state (sent/failed/failed-dnd), Exotel will do a POST callback to your end point if the URL is set as a parameter in the API. Content-type for the POST callback is application/x-www-form-urlencoded Below are the parameters:
  • SmsSid - The Sid (unique id) of the SMS that you got in response to your request
  • To - Mobile number to which SMS was sent
  • Status - one of: queued, sending, submitted, sent, failed-dnd, failed
curl -X POST https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send \
-d "From=0XXXXXX4890" \
-d "To[]=XXXXX30240" \
-d "To[]=XXXXX30241" \
-d "To[]=XXXXX30242" \
-d "Body=Hello World!"
            
var request = require('request');

var dataString = 'From=0XXXXXX4890&To[]=XXXXX30240&To[]=XXXXX30241&Body=Hello World!';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send',
    method: 'POST',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'From' => '0XXXXXX4890',
    'To' => array('XXXXX30240', 'XXXXX30241'),
    'Body' => 'Hello World!'
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send")
request = Net::HTTP::Post.new(uri)
request.body = "From=0XXXXXX4890&To[]=XXXXX30240&To[]=XXXXX30241&Body=Hello World!"

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = {
  'From': '0XXXXXX4890',
  'To': ['XXXXX30240', 'XXXXX30241'],
  'Body': 'Hello World!'
}

requests.post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/send', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The Sid is the unique identifier of the SMS and it will be useful to log this for future debugging
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
 <SMSMessage>
  <Sid>0b6c6a98f32682862ce6edf1bdab3526</Sid>
  <AccountSid>Exotel</AccountSid>
  <From>0XXXXXX4890/WEBDEV</From>
  <To>XXXXX30240</To>
  <DateCreated>2017-02-22 07:01:24</DateCreated>
  <DateUpdated>2017-02-22 07:01:24</DateUpdated>
  <DateSent/>
  <Body>Hello World!</Body>
  <Direction>outbound-api</Direction>
  <Uri>/v1/Accounts/Exotel/Sms/Messages/0b6c6a98f32682862ce6edf1bdab3526</Uri>
  <ApiVersion/>
  <Price/>
  <Status>queued</Status>
  <DetailedStatusCode>21010</DetailedStatusCode>
  <DetailedStatus>PENDING_TO_OPERATOR</DetailedStatus>
 </SMSMessage>
 <SMSMessage>
  <Sid>1393e66deb633e7297bcfa9a9da0bb37</Sid>
  <AccountSid>Exotel</AccountSid>
  <From>0XXXXXX4890/WEBDEV</From>
  <To>XXXXX30241</To>
  <DateCreated>2017-02-22 07:01:24</DateCreated>
  <DateUpdated>2017-02-22 07:01:24</DateUpdated>
  <DateSent/>
  <Body>Hello World!</Body>
  <Direction>outbound-api</Direction>
  <Uri>/v1/Accounts/Exotel/Sms/Messages/1393e66deb633e7297bcfa9a9da0bb37</Uri>
  <ApiVersion/>
  <Price/>
  <Status>queued</Status>
  <DetailedStatusCode>21010</DetailedStatusCode>
  <DetailedStatus>PENDING_TO_OPERATOR</DetailedStatus>
 </SMSMessage>
</TwilioResponse>
            
[
 {
    "SMSMessage": {
        "Sid": "0f477d60517e6e6a0f6d9a7e9af8630e",
        "AccountSid": "Exotel",
        "From": "0XXXXXX4890/WEBDEV",
        "To": "0XXXXX30240",
        "DateCreated": "2017-03-03 14:14:20",
        "DateUpdated": "2017-03-03 14:14:20",
        "DateSent": null,
        "Body": "Hello World!",
        "Direction": "outbound-api",
        "Uri": "/v1/Accounts/Exotel/Sms/Messages.json/0f477d60517e6e6a0f6d9a7e9af8630e",
        "ApiVersion": null,
        "Price": null,
        "Status": "queued",
        "DetailedStatusCode": "21010",
        "DetailedStatus": "PENDING_TO_OPERATOR"    
    }
 },
 {
    "SMSMessage": {
        "Sid": "1393e66deb633e7297bcfa9a9da0bb37",
        "AccountSid": "Exotel",
        "From": "0XXXXXX4890/WEBDEV",
        "To": "0XXXXX30240",
        "DateCreated": "2017-03-03 14:14:20",
        "DateUpdated": "2017-03-03 14:14:20",
        "DateSent": null,
        "Body": "Hello World!",
        "Direction": "outbound-api",
        "Uri": "/v1/Accounts/Exotel/Sms/Messages.json/1393e66deb633e7297bcfa9a9da0bb37",
        "ApiVersion": null,
        "Price": null,
        "Status": "queued",
        "DetailedStatusCode": "21010",
        "DetailedStatus": "PENDING_TO_OPERATOR"    
    }        
 }
]

Description of parameters mentioned in the above response:

Parameter NameType & Value
Sidstring; an alpha-numeric unique identifier of the SMS
AccountSidString; Your account identifier
FromString; It is of format <VN>/<SenderID> where <VN> is your Exotel Virtual Number/ExoPhone through which you are sending the SMS. <SenderID> is the SenderID via which this SMS was sent
ToString; The mobile number(s) to which the SMS was sent
DateCreatedTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was received at our server
DateUpdatedTime in format YYYY-MM-DD HH:mm:ss; The time when any property of this SMS was last updated by our server
DateSentTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was delivered to the recepient
BodyString; The body of the SMS message sent
StatusCan be of:
  • queued - This means that the SMS you have sent has been queued internally for delivery
  • sending - This means that we're in process of sending the SMS to upstream provider/gateway
  • submitted - This means that the SMS you have sent has been submitted from our system to SMS Gateway
  • sent - The SMS was successfully delivered to the handset
  • failed-dnd - The delivery of the SMS failed because the number belongs to the TRAI NCPR list. This is applicable only for promotional SMS
  • failed - The delivery of SMS failed. Please see DetailedStatusCode and DetailedStatus for further details.
DetailedStatusHuman readable word that explains what happened to the Message. Log these strings in your log files for grepping and debugging by a developer.
DetailedStatusCodeExotel’s Detailed Status code corresponding to the DetailedStatus. Use this field to build decision making in your code.
PriceDouble; If present, this will be the amount (in INR or USD) you have been charged for the SMS
Direction
  • incoming - incoming messages
  • outbound-api - messages initiated via the REST API
  • outbound-call - messages initiated during a call
  • outbound-reply - messages initiated in response to an incoming message
UriUri is the path of the SmsSid

Mapping and Description of status codes

Detailed Status CodeNature of Detailed Status CodeStatusDetailedStatusWhat it means
21010Intermediate, may change in futurequeuedPENDING_TO_OPERATORThe message is is being processed by Exotel.
21015Intermediate, may change in futuresendingSENDING_TO_OPERATORThe message has been processed by Exotel and is en-route to the operator.
21020Intermediate, may change in futuresubmittedPENDING_ON_OPERATORThe message has been successfully Submitted to the operator and is pending delivery. In India, Promotional SMS may be in this state if submitted outside permitted time (9AM to 9PM).
20005FinalsentDELIVERED_TO_HANDSETWe know with confidence that the message has been delivered to recipient's handset.
20006FinalsentDELIVERED_TO_OPERATORThe message has been delivered to operator. In some regions and routes, handset delivery status (DELIVERED_TO_HANDSET) is not available and hence this is the best we can ever report about the delivery status.
23005Finalfailed-dndFAILED_REJECTED_DNDThe message has been rejected as the end user is a subscriber of DND (Do Not Disturb) services.
23010FinalfailedFAILED_INVALID_DESTINATION_NUMBERThe destination number is incorrect, not SMS-enabled or is a PSTN landline.
23015FinalfailedFAILED_SPAM_DETECTEDOne of the most common reasons for SMS delivery failure is carrier level spam filters. Carriers have added systems and algorithms that detect spam content and then block these messages. Unfortunately, these filters are hidden, subject to carrier preferences, vary from carrier to carrier, and can be changed without notice.
23020FinalfailedFAILED_REJECTED_BLACKLISTYou tried to send a message to a blacklisted phone number. That is, the user has already sent a STOP/DND opt-out message and no longer wishes to receive messages from you.
24990FinalfailedFAILED_UNKNOWN_ERRORDelivering your message failed for reasons that are unknown to us and to our carriers. If you notice too many of these cases, please reach out to us.
23030FinalfailedFAILED_UNAVAILABLE_ROUTEThe carrier and fallback carriers were not able to deliver the SMS message because no route was available.
23035FinalfailedFAILED_SUBSCRIBER_UNAVAILABLEThis message was not delivered because subscriber was temporarily unavailable. For example, the receiving handset was out of coverage or switched off. This is a temporary failure, but a message sent to the same subscriber at a later point in time may get delivered.
23040FinalfailedFAILED_SUBSCRIBER_UNKNOWNSubscriber is unknown to the operators or no longer active.
23050FinalfailedFAILED_EXPIREDThe message was sent to the operator and may have been retried several times within the default network SMS expiration duration. The message request has now expired.
23060FinalfailedFAILED_REJECTEDFor a number of reasons, the message was rejected by Exotel or the operator.
24105FinalfailedFAILED_HANDSET_ERRORThe message was not delivered to the subscriber due to handset failure
24110FinalfailedFAILED_OPERATOR_ERRORThe message failed due to an issue at the operator end
23070FinalfailedFAILED_INVALID_MESSAGEThe message was rejected by the operator as Invalid. While Exotel will automatically split messages longer than 160 GSM 7-bit characters, or 70 unicode 16-bit characters into multipart SMS, Messages exceeding the allowed character limit of 2000 characters may also end in this state. Any request error related to the message, say unindentified character, may also fall under this bucket.
24010FinalfailedFAILED_SYSTEM_ERRORSMS failed while processing within Exotel system.
24120FinalfailedFAILED_SUBSCRIBER_ERRORAll subscriber or recipeient issues that are unrelated to the handset (For ex - Receiver does not have enough mobile balance to receive the SMS) may fall under this bucket.

Send Bulk SMS With Dynamic Content

This API will send SMSes to differrent numbers with different message content for each number. To send SMS through our API, you will need to make a HTTP POST request to

POST

https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/bulksend

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

The following are the POST parameters:

Parameter NameMandatory/OptionalValue
FromOptional
  • Specify one of your ExoPhones
  • For transactional SMSes, the SenderID (When you buy an ExoPhone, you will be asked to enter a 6-letter sender ID from which your SMSes will be sent. For Eg: LM-EXOTEL or LM-WEBDEV etc.) will be the one that corresponds to the ExoPhone
  • For promotional SMSes, the SenderID will anyways be a generic numeric one (Ex: LM-123456)
  • Will be used in cases where From is missing in Messages object
  • If not set, default approved SENDER ID as per account will be used
MessagesMandatoryArray of message objects, wherein each object contains parameters about individual SMS:
  • To (Mandatory) Mobile number to which SMS has to be sent. Preferably in E.164 format. If not set, our system will try to match it with a country and route the SMS
  • Body (Mandatory)Content of your SMS; Max Length of the body cannot exceed 2000 characters
  • From (Optional) ExoPhone or approved SENDER ID. If not provided, will use outer From
EncodingTypeOptionalMessage type of SMS; plain or unicode
PriorityOptionalPriority of the SMS; normal or high. Business critical operations like sending verification codes, confirming appointments etc which require immediate SMS delivery should opt for high priority.
StatusCallbackOptionalAfter every SMS reaches terminal state (sent/failed/failed-dnd), Exotel will do a POST callback to your end point if the URL is set as a parameter in the API. Content-type for the POST callback is application/x-www-form-urlencoded Below are the parameters:
  • SmsSid - The Sid (unique id) of the SMS that you got in response to your request
  • To - Mobile number to which SMS was sent
  • Status - one of: queued, sending, submitted, sent, failed-dnd, failed
curl -X POST https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/bulksend \
-d "From=0XXXXXX4890" \
-d "Messages[0][Body]=Hello World one" \
-d "Messages[0][To]=XXXXX30240" \
-d "Messages[1][Body]=Hello World two" \
-d "Messages[1][To]=XXXXX30241" \
            
var request = require('request');

var dataString = 'From=0XXXXXX4890&Messages[0][Body]=Hello World one&Messages[0][To]=XXXXX30240&Messages[1][Body]=Hello World two&Messages[1][To]=XXXXX30241';

var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/bulksend',
    method: 'POST',
    body: dataString
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);
            
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'From' => '0XXXXXX4890',
    'Messages' => array(array('To' => 'XXXXX30240', 'Body' => 'Hello World one'), array('To' => 'XXXXX30241', 'Body' => 'Hello World two')),
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/bulksend', $headers, $data);
            
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/bulksend")
request = Net::HTTP::Post.new(uri)
request.body = "From=0XXXXXX4890&Messages[0][Body]=Hello World one&Messages[0][To]=XXXXX30240&Messages[1][Body]=Hello World two&Messages[1][To]=XXXXX30241"

req_options = {
  use_ssl: uri.scheme == "https",
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

# response.code
# response.body
            
import requests

data = [
  'From': '0XXXXXX4890',
  ('Messages[0][Body]', 'Hello World one'),
  ('Messages[0][To]', 'XXXXX30240'),
  ('Messages[1][Body]', 'Hello World two'),
  ('Messages[1][To]', ' XXXXX30241'),
]

requests.post('https://<your_sid>:<your_token>@api.exotel.com/v1/Accounts/<your_sid>/Sms/bulksend', data=data)
            

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The Sid is the unique identifier of the SMS and it will be useful to log this for future debugging
  • the HTTP body will contain an XML similar to the one below
<?xml version="1.0" encoding="UTF-8"?>
<TwilioResponse>
 <SMSMessage>
  <Sid>0b6c6a98f32682862ce6edf1bdab3526</Sid>
  <AccountSid>Exotel</AccountSid>
  <From>0XXXXXX4890/WEBDEV</From>
  <To>XXXXX30240</To>
  <DateCreated>2017-02-22 07:01:24</DateCreated>
  <DateUpdated>2017-02-22 07:01:24</DateUpdated>
  <DateSent/>
  <Body>Hello World one</Body>
  <Direction>outbound-api</Direction>
  <Uri>/v1/Accounts/Exotel/Sms/bulksend/0b6c6a98f32682862ce6edf1bdab3526</Uri>
  <ApiVersion/>
  <Price/>
  <Status>queued</Status>
  <DetailedStatusCode>21010</DetailedStatusCode>
  <DetailedStatus>PENDING_TO_OPERATOR</DetailedStatus>
 </SMSMessage>
 <SMSMessage>
  <Sid>1393e66deb633e7297bcfa9a9da0bb37</Sid>
  <AccountSid>Exotel</AccountSid>
  <From>0XXXXXX4890/WEBDEV</From>
  <To>XXXXX30241</To>
  <DateCreated>2017-02-22 07:01:24</DateCreated>
  <DateUpdated>2017-02-22 07:01:24</DateUpdated>
  <DateSent/>
  <Body>Hello World!</Body>
  <Direction>outbound-api</Direction>
  <Uri>/v1/Accounts/Exotel/Sms/bulksend/1393e66deb633e7297bcfa9a9da0bb37</Uri>
  <ApiVersion/>
  <Price/>
  <Status>queued</Status>
  <DetailedStatusCode>21010</DetailedStatusCode>
  <DetailedStatus>PENDING_TO_OPERATOR</DetailedStatus>
 </SMSMessage>
</TwilioResponse>
            
[
 {
    "SMSMessage": {
        "Sid": "0f477d60517e6e6a0f6d9a7e9af8630e",
        "AccountSid": "Exotel",
        "From": "0XXXXXX4890/WEBDEV",
        "To": "0XXXXX30240",
        "DateCreated": "2017-03-03 14:14:20",
        "DateUpdated": "2017-03-03 14:14:20",
        "DateSent": null,
        "Body": "Hello World one",
        "Direction": "outbound-api",
        "Uri": "/v1/Accounts/Exotel/Sms/bulksend.json/0f477d60517e6e6a0f6d9a7e9af8630e",
        "ApiVersion": null,
        "Price": null,
        "Status": "queued",
        "DetailedStatusCode": "21010",
        "DetailedStatus": "PENDING_TO_OPERATOR"    
    }
 },
 {
    "SMSMessage": {
        "Sid": "1393e66deb633e7297bcfa9a9da0bb37",
        "AccountSid": "Exotel",
        "From": "0XXXXXX4890/WEBDEV",
        "To": "0XXXXX30241",
        "DateCreated": "2017-03-03 14:14:20",
        "DateUpdated": "2017-03-03 14:14:20",
        "DateSent": null,
        "Body": "Hello World two",
        "Direction": "outbound-api",
        "Uri": "/v1/Accounts/Exotel/Sms/bulksend.json/1393e66deb633e7297bcfa9a9da0bb37",
        "ApiVersion": null,
        "Price": null,
        "Status": "queued",
        "DetailedStatusCode": "21010",
        "DetailedStatus": "PENDING_TO_OPERATOR"    
    }        
 }
]

Description of parameters mentioned in the above response:

Parameter NameType & Value
Sidstring; an alpha-numeric unique identifier of the SMS
AccountSidString; Your account identifier
FromString; It is of format <VN>/<SenderID> where <VN> is your Exotel Virtual Number/ExoPhone through which you are sending the SMS. <SenderID> is the SenderID via which this SMS was sent
ToString; The mobile number(s) to which the SMS was sent
DateCreatedTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was received at our server
DateUpdatedTime in format YYYY-MM-DD HH:mm:ss; The time when any property of this SMS was last updated by our server
DateSentTime in format YYYY-MM-DD HH:mm:ss; The time when the SMS was delivered to the recepient
BodyString; The body of the SMS message sent
StatusCan be of:
  • queued - This means that the SMS you have sent has been queued internally for delivery
  • sending - This means that we're in process of sending the SMS to upstream provider/gateway
  • submitted - This means that the SMS you have sent has been submitted from our system to SMS Gateway
  • sent - The SMS was successfully delivered to the handset
  • failed-dnd - The delivery of the SMS failed because the number belongs to the TRAI NCPR list. This is applicable only for promotional SMS
  • failed - The delivery of SMS failed. Please see DetailedStatusCode and DetailedStatus for further details.
DetailedStatusHuman readable word that explains what happened to the Message. Log these strings in your log files for grepping and debugging by a developer.
DetailedStatusCodeExotel’s Detailed Status code corresponding to the DetailedStatus. Use this field to build decision making in your code.
PriceDouble; If present, this will be the amount (in INR or USD) you have been charged for the SMS
Direction
  • incoming - incoming messages
  • outbound-api - messages initiated via the REST API
  • outbound-call - messages initiated during a call
  • outbound-reply - messages initiated in response to an incoming message
UriUri is the path of the SmsSid

Mapping and Description of status codes

Detailed Status CodeNature of Detailed Status CodeStatusDetailedStatusWhat it means
21010Intermediate, may change in futurequeuedPENDING_TO_OPERATORThe message is is being processed by Exotel.
21015Intermediate, may change in futuresendingSENDING_TO_OPERATORThe message has been processed by Exotel and is en-route to the operator.
21020Intermediate, may change in futuresubmittedPENDING_ON_OPERATORThe message has been successfully Submitted to the operator and is pending delivery. In India, Promotional SMS may be in this state if submitted outside permitted time (9AM to 9PM).
20005FinalsentDELIVERED_TO_HANDSETWe know with confidence that the message has been delivered to recipient's handset.
20006FinalsentDELIVERED_TO_OPERATORThe message has been delivered to operator. In some regions and routes, handset delivery status (DELIVERED_TO_HANDSET) is not available and hence this is the best we can ever report about the delivery status.
23005Finalfailed-dndFAILED_REJECTED_DNDThe message has been rejected as the end user is a subscriber of DND (Do Not Disturb) services.
23010FinalfailedFAILED_INVALID_DESTINATION_NUMBERThe destination number is incorrect, not SMS-enabled or is a PSTN landline.
23015FinalfailedFAILED_SPAM_DETECTEDOne of the most common reasons for SMS delivery failure is carrier level spam filters. Carriers have added systems and algorithms that detect spam content and then block these messages. Unfortunately, these filters are hidden, subject to carrier preferences, vary from carrier to carrier, and can be changed without notice.
23020FinalfailedFAILED_REJECTED_BLACKLISTYou tried to send a message to a blacklisted phone number. That is, the user has already sent a STOP/DND opt-out message and no longer wishes to receive messages from you.
24990FinalfailedFAILED_UNKNOWN_ERRORDelivering your message failed for reasons that are unknown to us and to our carriers. If you notice too many of these cases, please reach out to us.
23030FinalfailedFAILED_UNAVAILABLE_ROUTEThe carrier and fallback carriers were not able to deliver the SMS message because no route was available.
23035FinalfailedFAILED_SUBSCRIBER_UNAVAILABLEThis message was not delivered because subscriber was temporarily unavailable. For example, the receiving handset was out of coverage or switched off. This is a temporary failure, but a message sent to the same subscriber at a later point in time may get delivered.
23040FinalfailedFAILED_SUBSCRIBER_UNKNOWNSubscriber is unknown to the operators or no longer active.
23050FinalfailedFAILED_EXPIREDThe message was sent to the operator and may have been retried several times within the default network SMS expiration duration. The message request has now expired.
23060FinalfailedFAILED_REJECTEDFor a number of reasons, the message was rejected by Exotel or the operator.
24105FinalfailedFAILED_HANDSET_ERRORThe message was not delivered to the subscriber due to handset failure
24110FinalfailedFAILED_OPERATOR_ERRORThe message failed due to an issue at the operator end
23070FinalfailedFAILED_INVALID_MESSAGEThe message was rejected by the operator as Invalid. While Exotel will automatically split messages longer than 160 GSM 7-bit characters, or 70 unicode 16-bit characters into multipart SMS, Messages exceeding the allowed character limit of 2000 characters may also end in this state. Any request error related to the message, say unindentified character, may also fall under this bucket.
24010FinalfailedFAILED_SYSTEM_ERRORSMS failed while processing within Exotel system.
24120FinalfailedFAILED_SUBSCRIBER_ERRORAll subscriber or recipeient issues that are unrelated to the handset (For ex - Receiver does not have enough mobile balance to receive the SMS) may fall under this bucket.

Available ExoPhones
Beta

This API will list the ExoPhone resources and get the Exophones that are avalable to use based on the ISO Country Code and Type. In case the country you are looking for is not available then please contact our sales or support teams.

The ExoPhone types are:

  • Landline
  • Mobile
  • TollFree

ExoPhone Resources By Country & Type

This API will list the ExoPhone resources that are available to use based on ISO Country Code and Type. To get a list, you will need to make an HTTP GET request to:

GET

https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

curl -X GET https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers 
var request = require('request');
var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers'
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}
request(options, callback);
    
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers', $headers);
    
require 'net/http'
require 'uri'
uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers")
response = Net::HTTP.get_response(uri)
# response.code
# response.body
    
import requests
requests.get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers')
    

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an JSON similar to the one below
{
  "uri": "/v2_beta/Accounts/Exotel/AvailablePhoneNumbers",
  "countries": [
    {
      "country_code": "IN",
      "country": "India",
      "uri": "/v2_beta/Accounts/Exotel/AvailablePhoneNumbers/IN",
      "subresource_uris": {
        "Landline": "/v2_beta/Accounts/Exotel/AvailablePhoneNumbers/IN/Landline",
        "Mobile": "/v2_beta/Accounts/Exotel/AvailablePhoneNumbers/IN/Mobile",
        "TollFree": "/v2_beta/Accounts/Exotel/AvailablePhoneNumbers/IN/TollFree"
      }
    }
  ]
}

Description of parameters mentioned in the above response:

Parameter NameType & Value
uriThe resource uri
countriesCountry subresource list
country_codeISO Country Code
countryCountry name
subresource_urisList of subresource_uris which can be used to get the numbers list

ExoPhones for a Country & Type

To get a list of all the ExoPhones for a give ISO Country Code & Type, you need to make an HTTP GET request to:

GET

https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers/<ISOCountryCode>/Landline

The following query parameters are supported on the GET request.

Parameter NameMandatory/OptionalValue
IncomingSMSOptionalGet only numbers that support incoming SMS.
InRegionOptionalGet only numbers in the specified telecom circle. This filter is not applicable in all countries. For India, the currently supported regions are:
  • AP - Andhra Pradesh Circle
  • AS - Assam
  • BR - Bihar
  • DL - Delhi Circle
  • GJ - Gujarat
  • HP - Himachal Pradesh
  • HR - Haryana
  • JK - Jammu and Kashmir
  • KA - Karnataka Circle
  • KL - Kerala
  • KO - Kolkata
  • MH - Maharashtra
  • MP - Madhya Pradesh
  • MU - Mumbai Circle
  • NE - North East
  • OR - Orissa
  • PB - Punjab
  • RJ - Rajasthan
  • TN - Tamilnadu
  • UE - Uttar Pradesh East
  • UW - Uttar Pradesh West
  • WB - West Bengal
ContainsOptionalGet numbers that contains the specified substring.
curl -X GET https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers/<iso_country_code>/<number_type>
var request = require('request');

var options = {
url: 'https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers/<iso_country_code>/<number_type>'
};

function callback(error, response, body) {
if (!error && response.statusCode == 200) {
  console.log(body);
}
}

request(options, callback);
      
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers/<iso_country_code>/<number_type>', $headers);
      
require 'net/http'
require 'uri'

uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers/<iso_country_code>/<number_type>" )
response = Net::HTTP.get_response(uri)

# response.code
# response.body
      
import requests

requests.get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/AvailablePhoneNumbers/<iso_country_code>/<number_type>')
      

HTTP Response:

  • On success, the HTTP response status code will be 200
  • the HTTP body will contain an JSON similar to the one below
[
  {
    "friendly_name": "+60XXXXXXX1",
    "phone_number": "+60XXXXXXXX1",
    "capabilities": {
      "sms": false,
      "voice": true
    },
    "country": "MY",
    "region": "MY",
    "one_time_price": "0.000000",
    "rental_price": "0.000000",
    "incoming_rate": "0.000000",
    "incoming_pulse": "60",
    "number_type": "Landline",
    "vanity_number": false
  },
  {
    "friendly_name": "+60XXXXXXXX2",
    "phone_number": "+60XXXXXXXX2",
    "capabilities": {
      "sms": false,
      "voice": true
    },
    "country": "MY",
    "region": "MY",
    "one_time_price": "0.000000",
    "rental_price": "0.000000",
    "incoming_rate": "0.000000",
    "incoming_pulse": "60",
    "number_type": "Landline",
    "vanity_number": false
  }
]
      

Description of parameters mentioned in the above response:

Parameter NameType & Value
friendly_nameA user friendly identifier for a number
phone_numberThe phone number
capabilitiesSupported capabilities on a number
  • voice - True if incoming calls are supported on this number
  • sms - True if incoming SMS is supporter on this number
countryThe ISO 3166-1 alpha-2 country code to which the number belongs to
regionThe telecom service area to which the number belongs to.
one_time_priceThe one time purchase cost associated with the number.
rental_priceThe rental cost associated with the number.
incoming_rateThe rate per pulse for an incoming call.
incoming_pulseThe telephone pulse rate.
number_typeThe type of the number.
vanity_numberThese are easily memorizable numbers. Eg: 1-800-Flowers

Get an ExoPhone
Beta

To begin using a new ExoPhone, make an HTTP POST request to:

POST

https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard.

The following are the POST parameters:

Parameter NameMandatory/OptionalValue
PhoneNumberMandatoryThe ExoPhone that you wish to get.
VoiceUrlOptionalThe VoiceURL to be associated to this number. The URL is of the form: http://my.exotel.com/{your_sid}/exoml/start_voice/{app_id} where app_id is the identifier of the flow (or applet) that you want to connect to once the From number picks up the call. You can get the app_id from your Exotel Dashboard.
SMSUrlOptionalThe SMSUrl to be associated to this number. The URL is of the form: http://my.exotel.com/{your_sid}/exoml/start_sms/{app_id} where app_id is the identifier of the flow (or applet) that you want to connect to once an incoming SMS is received.
FriendlyNameOptionalA friendly name that can be used to identify this number easily.
curl -X POST https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers \
  -d "PhoneNumber=XXXXX30240"
    
var request = require('request');
var dataString = 'PhoneNumber=XXXXX30240';
var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers',
    method: 'POST',
    body: dataString
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}
request(options, callback);
    
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'PhoneNumber' => 'XXXXX30240'
);
$response = Requests::post('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers', $headers, $data);
    
require 'net/http'
require 'uri'
uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers")
request = Net::HTTP::Post.new(uri)
request.set_form_data(
  "PhoneNumber" => "XXXXX30240",
)
req_options = {
  use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end
# response.code
# response.body
    
import requests
data = {
  'PhoneNumber': 'XXXXX30240'
}
requests.post('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers', data=data)
    

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The sid is the unique identifier of the number
  • the HTTP body will contain an JSON similar to the one below:
{
  "sid": "9eeafc8ab479a386dc95f854f9d7cd8a",
  "date_created": "2016-11-09 13:48:12",
  "date_updated": "2017-03-30 14:19:02",
  "account_sid": "Exotel",
  "friendly_name": "XXXXX30240",
  "phone_number": "+91XXXX30240",
  "capabilities": {
      "voice": true,
      "sms": true
  },
  "country": "IN",
  "region": "WB",
  "one_time_price": "0.000000",
  "rental_price": "499.000000",
  "incoming_rate": "0.000000",
  "incoming_pulse": "60",
  "currency": "INR",
  "number_type": "Landline",
  "vanity_number": false,
  "voice_url": "https://my.exotel.in/Exotel/exoml/start_voice/12XX48",
  "sms_url": "https://my.exotel.in/Exotel/exoml/start_sms/22XX39",
  "uri": "/v2_beta/Accounts/Exotel/IncomingPhoneNumbers/9eeafc8ab479a386dc95f854f9d7cd8a"
}
    

Description of IncomingPhoneNumbers Parameters:

Parameter NameType & Value
sidstring; an alpha-numeric unique identifier of the number
date_createdTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the number was purchases
date_updatedTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the details of the number was last updated
account_sidExotel account SID
phone_numberThe phone number that was purchased
friendly_nameA freindly name that can be used to identify the number
capabilitiesThese are the capabilities that are supported on this number:
  • voice - Boolean that indicates if incoming voice calls are supported on the number
  • sms - Boolean that indicates if incoming SMS is supported on the number
countryISO Country Code to which this number belongs to
regionThe telecom circle this number belongs to
one_time_priceOne time cost incurred while purchasing this number
rental_priceDouble; Recurring monthly rental associated with this number
incoming_rateDouble; The per pulse cost for incoming calls
incoming_pulseDouble; The duration of one pulse in seconds
currencyDouble; The currency in which this number is billed
number_typeDouble; The type of the number
vanity_numberBoolean; Indicates if this number is a vanity number
voice_urlstring; The Url to the flow to which incoming calls are connected to
sms_urlstring; The Url to the flow to which incoming SMS are connected to
uristring; The Url to the flow to which incoming calls are connected to

Assign number to a flow
Beta

To assign an ExoPhone to a flow you need to make a HTTP PUT request to:

PUT

https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard. Replace <exophone_sid> with the ExoPhone SID of the ExoPhone you wish to update.

The following are the PUT parameters:

Parameter NameMandatory/OptionalValue
VoiceUrlOptionalThe VoiceURL to be associated to this number. The URL is of the form: http://my.exotel.com/{your_sid}/exoml/start_voice/{app_id} where app_id is the identifier of the flow (or applet) that you want to connect to once the From number picks up the call. You can get the app_id from your Exotel Dashboard.
SMSUrlOptionalThe SMSUrl to be associated to this number. The URL is of the form: http://my.exotel.com/{your_sid}/exoml/start_sms/{app_id} where app_id is the identifier of the flow (or applet) that you want to connect to once an incoming SMS is received.
FriendlyNameOptionalA friendly name that can be used to identify this number easily.
curl -X PUT https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid< \
  -d "FriendlyName=Sales"
    
var request = require('request');
var dataString = 'FriendlyName=Sales';
var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid<',
    method: 'PUT',
    body: dataString
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}
request(options, callback);
    
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$data = array(
    'FriendlyName' => 'Sales'
);
$response = Requests::put('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid<', $headers, $data);
    
require 'net/http'
require 'uri'
uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid<")
request = Net::HTTP::Put.new(uri)
request.set_form_data(
  "FriendlyName" => "Sales",
)
req_options = {
  use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end
# response.code
# response.body
    
import requests
data = {
  'FriendlyName': 'Sales'
}
requests.put('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid<', data=data)
    

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The sid is the unique identifier of the number
  • the HTTP body will contain an JSON similar to the one below:
{
  "sid": "9eeafc8ab479a386dc95f854f9d7cd8a",
  "date_created": "2016-11-09 13:48:12",
  "date_updated": "2017-03-30 14:19:02",
  "account_sid": "Exotel",
  "friendly_name": "Sales",
  "phone_number": "+91XXXXXXX40",
  "capabilities": {
      "voice": true,
      "sms": true
  },
  "country": "IN",
  "region": "WB",
  "one_time_price": "0.000000",
  "rental_price": "0.000000",
  "incoming_rate": "0.000000",
  "incoming_pulse": "60",
  "currency": "INR",
  "number_type": "Landline",
  "vanity_number": false,
  "voice_url": "https://my.exotel.in/Exotel/exoml/start_voice/1XXXX8",
  "sms_url": "https://my.exotel.in/Exotel/exoml/start_sms/2XXXX9",
  "uri": "/v2_beta/Accounts/Exotel/IncomingPhoneNumbers/9eeafc8ab479a386dc95f854f9d7cd8a"
}
    

Description of IncomingPhoneNumbers Parameters:

Parameter NameType & Value
sidstring; an alpha-numeric unique identifier of the number
date_createdTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the number was purchases
date_updatedTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the details of the number was last updated
account_sidExotel account SID
phone_numberThe phone number that was purchased
friendly_nameA freindly name that can be used to identify the number
PhoneNumberSidThis is your ExoPhone/Exotel Virtual Number
capabilitiesThese are the capabilities that are supported on this number:
  • voice - Boolean that indicates if incoming voice calls are supported on the number
  • sms - Boolean that indicates if incoming SMS is supported on the number
countryISO Country Code to which this number belongs to
regionThe telecom circle this number belongs to
one_time_priceOne time cost incurred while purchasing this number
rental_priceDouble; Recurring monthly rental associated with this number
incoming_rateDouble; The per pulse cost for incoming calls
incoming_pulseDouble; The duration of one pulse in seconds
currencyDouble; The currency in which this number is billed
number_typeDouble; The type of the number
vanity_numberBoolean; Indicates if this number is a vanity number
voice_urlstring; The Url to the flow to which incoming calls are connected to
sms_urlstring; The Url to the flow to which incoming SMS are connected to
uristring; The Url to the flow to which incoming calls are connected to

ExoPhone Details
Beta

List all ExoPhones

To get a list of all the ExoPhone numbers that have been assigned to an account, you will need to make a HTTP GET request to:

GET

https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard

curl -X GET https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers 
var request = require('request');
var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers'
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}
request(options, callback);
    
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers', $headers);
    
require 'net/http'
require 'uri'
uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers")
response = Net::HTTP.get_response(uri)
# response.code
# response.body
    
import requests
requests.get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers')
    

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The sid is the unique identifier of the number
  • the HTTP body will contain an JSON similar to the one below:
{
  "page": 0,
  "page_size": 50,
  "uri": "http://twilix.exotel.com/v2_beta/Accounts/Exotel/IncomingPhoneNumbers?Page=0&PageSize=50",
  "first_page_uri": "http://twilix.exotel.com/v2_beta/Accounts/Exotel/IncomingPhoneNumbers?Page=0&PageSize=50",
  "next_page_uri": "http://twilix.exotel.com/v2_beta/Accounts/Exotel/IncomingPhoneNumbers?Page=1&PageSize=50",
  "previous_page_uri": null,
  "incoming_phone_numbers": [
    {
      "sid": "011XXXXXXX1",
      "date_created": "2016-03-04 17:31:50",
      "date_updated": "2017-09-22 22:47:00",
      "account_sid": "Exotel",
      "friendly_name": "011XXXXXXX6",
      "phone_number": "+9111XXXXXXX6",
      "capabilities": {
        "voice": true,
        "sms": true
      },
      "country": "IN",
      "region": "DL",
      "one_time_price": "0.000000",
      "rental_price": "0.000000",
      "incoming_rate": "0.000000",
      "incoming_pulse": "60",
      "currency": "INR",
      "number_type": "Landline",
      "vanity_number": false,
      "voice_url": null,
      "sms_url": null,
      "uri": "/v2_beta/Accounts/Exotel/IncomingPhoneNumbers/011XXXXXXX6"
    },
    {
      "sid": "011XXXXXXX0",
      "date_created": "2016-04-07 12:13:20",
      "date_updated": "2016-04-07 12:13:30",
      "account_sid": "Exotel",
      "friendly_name": "011XXXXXXX0",
      "phone_number": "+911XXXXXXXX0",
      "capabilities": {
        "voice": true,
        "sms": true
      },
      "country": "IN",
      "region": "DL",
      "one_time_price": "0.000000",
      "rental_price": "0.000000",
      "incoming_rate": "0.000000",
      "incoming_pulse": "60",
      "currency": "INR",
      "number_type": "Landline",
      "vanity_number": false,
      "voice_url": "http://my.exotel.in/Exotel/exoml/start_voice/7XXX1",
      "sms_url": "http://my.exotel.in/Exotel/exoml/start_sms/7XXX1",
      "uri": "/v2_beta/Accounts/Exotel/IncomingPhoneNumbers/011XXXXXXX0"
    }
  ]
}
    

Description of Parameters:

Parameter NameType & Value
sidstring; an alpha-numeric unique identifier of the number
date_createdTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the number was purchases
date_updatedTime in format YYYY-MM-DD HH:mm:ss; Date and time at which the details of the number was last updated
account_sidExotel account SID
phone_numberThe phone number that was purchased
friendly_nameA freindly name that can be used to identify the number
capabilitiesThese are the capabilities that are supported on this number:
  • voice - Boolean that indicates if incoming voice calls are supported on the number
  • sms - Boolean that indicates if incoming SMS is supported on the number
countryISO Country Code to which this number belongs to
regionThe telecom circle this number belongs to
one_time_priceOne time cost incurred while purchasing this number
rental_priceDouble; Recurring monthly rental associated with this number
incoming_rateDouble; The per pulse cost for incoming calls
incoming_pulseDouble; The duration of one pulse in seconds
currencyDouble; The currency in which this number is billed
number_typeDouble; The type of the number
vanity_numberBoolean; Indicates if this number is a vanity number
voice_urlstring; The Url to the flow to which incoming calls are connected to
sms_urlstring; The Url to the flow to which incoming SMS are connected to
uristring; The Url to the flow to which incoming calls are connected to

Get Details of an ExoPhone

To get the details of a specific ExoPhone number of an account, make an HTTP GET request to:

GET

https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard. Replace <exophone_sid> with the ExoPhone sid.

curl -X GET https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>
var request = require('request');
var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>'
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}
request(options, callback);
    
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>', $headers);
    
require 'net/http'
require 'uri'
uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>")
response = Net::HTTP.get_response(uri)
# response.code
# response.body
    
import requests
requests.get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>')
    

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The sid is the unique identifier of the number
  • the HTTP body will contain an JSON similar to the one below:
{
  "sid": "9eeafc8ab479a386dc95f854f9d7cd8a",
  "date_created": "2016-11-09 13:48:12",
  "date_updated": "2017-03-30 14:19:02",
  "account_sid": "Exotel",
  "friendly_name": "XXXXX30240",
  "phone_number": "+91XXXX30240",
  "capabilities": {
      "voice": true,
      "sms": true
  },
  "country": "IN",
  "region": "WB",
  "one_time_price": "0.000000",
  "rental_price": "499.000000",
  "incoming_rate": "0.000000",
  "incoming_pulse": "60",
  "currency": "INR",
  "number_type": "Landline",
  "vanity_number": false,
  "voice_url": "https://my.exotel.in/Exotel/exoml/start_voice/12XX48",
  "sms_url": "https://my.exotel.in/Exotel/exoml/start_sms/22XX39",
  "uri": "/v2_beta/Accounts/Exotel/IncomingPhoneNumbers/9eeafc8ab479a386dc95f854f9d7cd8a"
}
    

Delete a ExoPhone Number
Beta

To release a number from your account, you need to make a HTTP DELETE request to:

DELETE

https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>

curl -X DELETE https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>
var request = require('request');
var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>'
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}
request(options, callback);
    
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>', $headers);
    
require 'net/http'
require 'uri'
uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<number_sid>")
response = Net::HTTP.get_response(uri)
# response.code
# response.body
    
import requests
requests.delete('https://<your_sid>:<your_token>@api.exotel.com/v2_beta/Accounts/<your_sid>/IncomingPhoneNumbers/<exophone_sid>')
    

HTTP Response:

  • On success, the HTTP response status code will be 202
  • The sid is the unique identifier of the number
  • the HTTP body will contain an JSON similar to the one below:
{
  "Status":202,
  "Message":"Accepted"
}

Heartbeat Subscription
Beta

Heartbeat API notifies the ‘health’ of an Exophone in real time based on which actions can be taken at your end. To subscribe to Heartbeat, you need to put a working HTTP URL (it should return 200 OK on POST request) in the Notifications Settings of your Dashboard along with frequency mentioned in minutes. The URL endpoint will receive heartbeat notifications continously at the frequency you set.

Heartbeat Subscription Setting


Heartbeat Webhook
Beta

This webhook (HTTP Push API) will ping information about your ExoPhone health every nth minute as configured. If some ExoPhones are facing connectivity issues, we will provide details about those ExoPhones alone. You can use the Get ExoPhone Details API described in next section for further connectivity information about an ExoPhone.

Description of parameters which will be set in heartbeat requests to your endpoint:

Parameter NameDescription

timestamp

This denotes the time when a particular heartbeat request was generated in our system.
Date Time Format: RFC 3339
Example: 2018-08-22T15:19:23Z

status_type

This will provide an overall state of all your ExoPhones combined. Possible values

  • OK - This denotes that all your ExoPhones are healthy and there is no connectivity issue identified by our system
  • WARNING - One or more ExoPhones' health is affected in either incoming/outgoing or both.
  • CRITICAL - All your ExoPhones health is affected in either incoming/outgoing or both
  • PAYLOAD_TOO_LARGE - It indicates that the maximum payload size limit (10MB) this method supports has breached. You may observe this error if you have signficantly large quantity of ExoPhones in your account. In case you observe this, you can use Get Exophone Details to know your ExoPhones health.

incoming_affected

Array; List of unique SIDs denoting ExoPhone(s) for which incoming call connectivity is affected

outgoing_affected

Array; List of unique SIDs denoting ExoPhone(s) for which outgoing call connectivity is affected

data

This block contains comma separated nested JSON blocks denoting information per ExoPhone which is having connectivity issues as mentioned in incoming_affected or outgoing_affected array.


phone_number_sid (key): Unique string which identifies the ExoPhone owned by you. This may not always be same as your phone number. You can find out your ExoPhone SID by triggering a GET request using your auth credentials on https://api.exotel.com/v2/accounts/<account_sid>/incoming-phone-numbers

It’s value will be a nested JSON containing below:

  • phone_number - Denoting the phone_number of the ExoPhone in E.164 format. This can be different than the SID of the phone number.


For example, 02030090005 denotes the phone_number_sid (key) and phone_number is present as parameter within it in E.164 format.

"02030090005":{ 
    "phone_number": "+912030090005"
}


Note: There could be multiple blocks depending on numbers present in incoming_affected and outgoing_affected list.

Example webhook payload with possible scenarios:

If everything is working fine i.e. all ExoPhones are healthy (OK):

{
    "timestamp": "2018-08-22T15:19:23Z",	
    "status_type": "OK",
    "incoming_affected": null,
    "outgoing_affected": null,
    "data": {}
}

If some ExoPhones connectivity is affected (WARNING):

{  
   "timestamp": "2018-08-22T15:19:23Z>",
   "status_type":"WARNING",
   "incoming_affected":[ 
      "07930061010"
   ],
   "outgoing_affected": null,
   "data":{  
      "07930061010":{  
         "phone_number": "+917930061010",
      }
   }
}

If all ExoPhones connectivity is affected (CRITICAL):

{  
   "timestamp": "2018-08-22T15:19:23Z",
   "status_type":"CRITICAL",
   "incoming_affected":[ 
      "07930061010",
      "08030752522"
   ],
   "outgoing_affected":[  
      "07930061010"
   ],
   "data":{  
      "07930061010":{  
         "phone_number": "+917930061010",
      },
      "08030752522":{  
          "phone_number": "+918030752522",
      }
   }
}

Responding to a heartbeat request

The HTTP Response for acknowledging the heartbeat webhook request should be 200 OK. All other non-2XX HTTP codes or if your server is unable to respond timely will indicate that you have not received the heartbeat and we will retry. In such retry cases, your server should be able to handle subsequent requests of the same heartbeat and the timestamp field in the heartbeat payload can be used to uniquely identify the most recent heartbeat.

Retries and timeouts

If your server needs to perform any complex logic, or make internal network calls, it is possible that the heartbeat webhook request might time out. For that reason, you might want to have your webhook endpoint immediately acknowledge receipt by returning a 2XX HTTP status code, and then perform the rest of its operations.

Guidelines on usage

You should consume Heartbeat Webhook to continuously be aware of your ExoPhones health status and take necessary actions. In case any of your ExoPhone faces an issue as reported by webhook, you can query the GET ExoPhone Details for fetching further details. The GET endpoint can also be used to pull status per ExoPhone in case the webhook is not consumed by your servers (Exotel not being able to send or because your server is unable to process). As a best practice, polling the GET endpoint is not recommended. Exotel will throttle requests to GET ExoPhone Details endpoint with HTTP Code 429.


Get Details of an ExoPhone
Beta

To get the details of a specific ExoPhone in your account including connectivity information, make an HTTP GET request to:

GET

https://<your_sid>:<your_token>@api.exotel.com/v2/accounts/<your_sid>/incoming-phone-numbers/<exophone_sid>

Replace <your_sid> and <your_token> with the values from the API Settings tab of your Exotel Dashboard. Replace <exophone_sid> with the ExoPhone sid.

curl -X GET https://<your_sid>:<your_token>@api.exotel.com/v2/accounts/<your_sid>/incoming-phone-numbers/<exophone_sid>
var request = require('request');
var options = {
    url: 'https://<your_sid>:<your_token>@api.exotel.com/v2/accounts/<your_sid>/incoming-phone-numbers/<exophone_sid>'
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}
request(options, callback);
    
<?php
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array();
$response = Requests::get('https://<your_sid>:<your_token>@api.exotel.com/v2/accounts/<your_sid>/incoming-phone-numbers/<exophone_sid>', $headers);
    
require 'net/http'
require 'uri'
uri = URI.parse("https://<your_sid>:<your_token>@api.exotel.com/v2/accounts/<your_sid>/incoming-phone-numbers/<exophone_sid>")
response = Net::HTTP.get_response(uri)
# response.code
# response.body
    
import requests
requests.get('https://<your_sid>:<your_token>@api.exotel.com/v2/accounts/<your_sid>/incoming-phone-numbers/<exophone_sid>')
    

HTTP Response:

  • On success, the HTTP response status code will be 200
  • The sid is the unique identifier of the number
  • the HTTP body will contain an JSON similar to the one below:
{
  "request_id": "0f403dff8d854ca08c570a94717aa7d9",
  "method": "GET",
  "http_code": 200,
  "metadata": {
    "page_size": 1,
    "page": 0
  },
  "response": [
    {
      "code": 200,
      "error_data": null,
      "status": "success",
      "data": {
        "sid": "01139585476",
        "date_created": "2018-08-22T12:22:49Z",
        "date_updated": "2018-08-24T11:25:49Z",
        "friendly_name": "01139585476",
        "account_sid": "Exotel",
        "phone_number": "+911139585476",
        "capabilities": {
          "voice": true
        },
        "country": "IN",
        "region": "DL",
        "one_time_price": "0.000000",
        "rental_price": "499.000000",
        "incoming_rate": "0.000000",
        "incoming_pulse": "60",
        "currency": "INR",
        "number_type": "Landline",
        "vanity_number": false,
        "voice_url": "https://my.exotel.com/Exotel/exoml/start_voice/XXX",
        "sms_url": "https://my.exotel.com/Exotel/exoml/start_sms/XXX",
        "uri": "/v2/accounts/Exotel/incoming-phone-numbers/01139585476",
        "connectivity": {
          "incoming_call": {
            "status": "active",
            "last_check_time": "2018-08-24T11:25:49Z",
            "alternate_exophone": null
          },
          "outgoing_call": {
            "status": "active",
            "last_check_time": "2018-08-24T11:25:49Z",
            "alternate_exophone": null
          }
        }
      }
    }
  ]
}
    

Description of Parameters:

Parameter NameDescription
request_idRandom string to uniquely identify the request
methodHTTP request method (GET, POST, PUT, DELETE)
http_codeHTTP response code for your request like 200, 404, 429, 500 etc.
metadataTo provide metadata about the response. In case of GET for pagination (bulk), it'll contain:
  • page_size - total number of items in a page
  • page - denotes page number
responseJSON array representing the response and contains below parameters:
  • code - response code of the block in the response array, can be different from the overall http code, like in case of partial success (207)
  • error_data - To be populated in case of errors like below
    "error_data": {
      "code": 1000,
      "description": "Not Found",
      "message": "Not Found"
    }
    
  • In case of no errors, it’ll be null.
  • status - success or failure, depicting the status of the block in the response array
  • data - This will contain the data part of the block of the response array depending on the API, below table describes what will be populated in case of GET IPN. Please note, this field can be null also in case of failures like 404.
sidString; An alpha-numeric unique identifier of the ExoPhone. This can be different than the ExoPhone itself.
date_createdTime in format: RFC 3339; Date and time at which the ExoPhone was added to the account
date_updatedTime in format: RFC 3339; Date and time at which the details of the ExoPhone was last updated
account_sidExotel account SID
phone_numberThe phone number value of the ExoPhone in E.164 format like +911139585476
friendly_nameA freindly name that can be used to identify the ExoPhone
capabilitiesThese are the capabilities that are supported on this ExoPhone:
  • voice - Boolean that indicates if incoming voice calls are supported on the ExoPhone
  • sms - Boolean that indicates if incoming SMS is supported on the ExoPhone
countryISO Country Code to which this ExoPhone belongs to
regionThe telecom circle this ExoPhone belongs to. Refer here for list of possible telecom circles.
one_time_priceOne time cost incurred while adding this ExoPhone to your account
rental_priceDouble; Recurring monthly rental associated with this ExoPhone
incoming_rateDouble; The per pulse cost for incoming calls
incoming_pulseDouble; The duration of one pulse in seconds
currencyDouble; The currency in which this ExoPhone is billed
number_typeDouble; The type of the ExoPhone
vanity_numberBoolean; Indicates if this ExoPhone is a vanity number
voice_urlstring; The Url to the flow to which incoming calls are connected to
sms_urlstring; The Url to the flow to which incoming SMS are connected to
uristring; The Url to the flow to which incoming calls are connected to
connectivityJSON block representing connectivity information about the ExoPhone. It contains incoming_call, outgoing_call blocks which represent connectivity information for incoming call and outgoing call respectively.

Description of 'connectivity' parameters:

Parameter NameDescription
statusIt represents the connectivity status for that functionality (incoming call or outgoing call). Possible values are
  • active: ExoPhone is healthy as per our monitoring system
  • major_outage: ExoPhone is inactive and calls are not connecting as per our monitoring system
  • partial_network_outage: ExoPhone is working partially and is down from/towards one or more operator connectivities. This would be populated once operator level connectivity monitoring information is exposed (yet to be released)
last_check_timeFormat: RFC 3339; timestamp representing when this number was checked last for connectivity
alternate_exophoneIf available, this will provide alternate ExoPhones in JSON array format which can be used if the given ExoPhone is down. If there are no alternate ExoPhones available it will be populated as null