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
https://<your_api_key>:<your_api_token><subdomain>/v1/Accounts/<your_sid>/Sms/send
If you’d prefer response in JSON format, just append .json at the end of the HTTP POST request.
Before you start sending transactional SMS through this API, please test whether your content is matching a template. Otherwise, the SMS will end up becoming promotional.
<your_api_key>
and <your_api_token>
with the API key and token created by you.<your_sid>
with your “Account sid”<subdomain>
with the region of your account
<your_api_key>
, <your_api_token>
and <your_sid>
are available in the API settings page of your Exotel Dashboard
The following are the POST parameters:
Parameter Name | Mandatory/Optional | Value |
---|---|---|
From | Mandatory |
Specify one of your ExoPhone or Sender ID (header) linked to it.
If your account doesn't have a valid Sender ID against the SMS body, API will return To view or configure your Sender IDs, refer here. If you are sending SMSs in India, please refer here to the new TRAI Guidelines and process (effective 1st June 2020). The Sender ID (From) should be linked with the SMS template as registered on DLT portal. |
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 To avoid SMS failure, make sure this exactly matches with SMS template added on Exotel Dashboard and is registered with operator DLT portal in case of India. |
EncodingType | Optional | Message type of SMS; plain or unicode |
ShortenUrl | Optional |
Whether to shorten the URLs present in the SMS. Can be: "true" or "false". |
ShortenUrlParams[Header] | Optional |
Applicable only for SMS sent by Indian businesses to Indian destination numbers. Header that is part of the whitelisted Shortened URL on the DLT(Distributed Ledger Technology) platform of your choice. Please ensure that this is an exact match with the header that is part of the whitelisted URL to avoid message failure |
ShortenUrlParams |
Optional |
Whether to track the URLs present in the SMS. Can be: "true" or "false". "ShortenUrl" needs to be "true" for Tracking to work. This feature is currently available to select customers. For early access, please fill this form. |
ShortenUrlParams [ClickTrackingCallbackUrl] |
Optional |
Once someone clicks on the shortened URL, Exotel will do a POST callback to your end point if the URL is set as a parameter in the API. Below are the parameters:
This feature is currently available to select customers. For early access, please fill this form. |
StatusCallback | Optional |
Once 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:
|
DltEntityId | Optional (Globally) Mandatory (India) |
Applicable only for SMS sent by Indian businesses to Indian destination numbers. |
DltTemplateId | Optional |
Applicable only for SMS sent by Indian businesses to Indian destination numbers. |
SmsType | Optional |
Applicable only for SMS sent by Indian businesses to Indian destination numbers. For International entities, the step to add a Template on the Exotel dashboard is mandatory. Possible values-
If not set or incorrectly passed, Exotel will look up if content matches Templates added on Exotel for fetching SMS Type and DLT details. |
CustomField | Optional |
Set a Custom Field relevant to your use case while sending an SMS. E.g Order ID, Payment ID, Login Attempt etc |
Priority | Optional |
Priority of the SMS; normal or high. Priority=high parameter should only be used for OTP SMSes (Bank or Delivery). Using it for any other SMS may impact your delivery |
curl -X POST https://<your_api_key>:<your_api_token><subdomain>/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_api_key>:<your_api_token><subdomain>/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_api_key>:<your_api_token><subdomain>/v1/Accounts/<your_sid>/Sms/send', $headers, $data);
import requests data = { 'From': '0XXXXXX4890', 'To': 'XXXXX30240', 'Body': 'Hello World!' } requests.post('https://<your_api_key>:<your_api_token><subdomain>/v1/Accounts/<your_sid>/Sms/send', data=data)
require 'net/http' require 'uri' uri = URI.parse("https://<your_api_key>:<your_api_token><subdomain>/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
curl -X POST https://<your_api_key>:<your_api_token><subdomain>/v1/Accounts/<your_sid>/Sms/send -d "From=0XXXXXX4890" -d "To=XXXXX30241" -d "Body=Hello World!" -d "ShortenUrl=true" -d "ShortenUrlParams[Header]=EXOTEL" -d "ShortenUrlParams[Tracking]=true" -d "ShortenUrlParams[ClickTrackingCallbackUrl]=https://www.google.co.in/"
var request = require('request'); var dataString = 'From=0XXXXXX4890&To=XXXXX30240&Body=Hello World!&ShortenUrl=true&ShortenUrlParams[Header]=EXOTEL&ShortenUrlParams[Tracking]=true&ShortenUrlParams[ClickTrackingCallbackUrl]=https://www.google.co.in/'; var options = { url: 'https://<your_api_key>:<your_api_token><subdomain>/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!', 'ShortenUrl' => 'true', 'ShortenUrlParams[Tracking]' => 'true', 'ShortenUrlParams[Header]' => 'EXOTEL', 'ShortenUrlParams[ClickTrackingCallbackUrl]' => 'https://www.google.co.in/' ); $response = Requests::post('https://<your_api_key>:<your_api_token><subdomain>/v1/Accounts/<your_sid>/Sms/send', $headers, $data);
import requests data = { 'From': '0XXXXXX4890', 'To': 'XXXXX30240', 'Body': 'Hello World!', 'ShortenUrl' : 'true', 'ShortenUrlParams[Header]' : 'EXOTEL', 'ShortenUrlParams[Tracking]' : 'true', 'ShortenUrlParams[ClickTrackingCallbackUrl]' : 'https://www.google.co.in/' } requests.post('https://<your_api_key>:<your_api_token><subdomain>/v1/Accounts/<your_sid>/Sms/send', data=data)
require 'net/http' require 'uri' uri = URI.parse("https://<your_api_key>:<your_api_token><subdomain>/v1/Accounts/<your_sid>/Sms/send") request = Net::HTTP::Post.new(uri) request.body = "From=0XXXXXX4890&To=XXXXX30240&Body=Hello World!&ShortenUrl=true&ShortenUrlParams[Header]=EXOTEL&ShortenUrlParams[Tracking]=true&ShortenUrlParams[ClickTrackingCallbackUrl]=https://www.google.co.in/" 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
HTTP Response:
{ "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/0f477d60517e6e6a0f6d9a7e9af8630e.json", "ApiVersion": null, "Price": null, "Status": "queued", "DetailedStatusCode": "21010", "DetailedStatus": "PENDING_TO_OPERATOR", "SmsUnits": null } }
<?xml version="1.0" encoding="UTF-8"?> <TwilioResponse> <SMSMessage> <Sid>0f477d60517e6e6a0f6d9a7e9af8630e</Sid> <AccountSid>Exotel</AccountSid> <From>0XXXXXX4890/WEBDEV</From> <To>XXXXX30240</To> <DateCreated>2017-03-03 14:14:20</DateCreated> <DateUpdated>2017-03-03 14:14:20</DateUpdated> <DateSent/> <Body>Hello World!</Body> <Direction>outbound-api</Direction> <Uri>/v1/Accounts/Exotel/SMS/Messages/0f477d60517e6e6a0f6d9a7e9af8630e</Uri> <ApiVersion/> <Price/> <Status>queued</Status> <DetailedStatusCode>21010</DetailedStatusCode> <DetailedStatus>PENDING_TO_OPERATOR</DetailedStatus> <SmsUnits/> </SMSMessage> </TwilioResponse>
Description of parameters mentioned in the above response:
Parameter Name |
Type & Value |
Sid |
string; an alpha-numeric unique identifier of the SMS |
AccountSid |
String; Your account identifier |
From |
String; 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 |
To |
String; The mobile number(s) to which the SMS was sent |
DateCreated |
Time in format YYYY-MM-DD HH:mm:ss; The time when the SMS was received at our server |
DateUpdated |
Time in format YYYY-MM-DD HH:mm:ss; The time when any property of this SMS was last updated by our server |
DateSent |
Time in format YYYY-MM-DD HH:mm:ss; The time when the SMS was delivered to the recepient |
Body |
String; The body of the SMS message sent |
Status |
Can be of:
|
DetailedStatus |
Human readable word that explains what happened to the Message. Log these strings in your log files for grepping and debugging by a developer. |
DetailedStatusCode |
Exotel’s Detailed Status code corresponding to the DetailedStatus. Use this field to build decision making in your code. |
Price |
Double; If present, this will be the amount (in INR or USD) you have been charged for the SMS |
Direction |
|
Uri |
Uri is the path of the SmsSid |
SmsUnits |
The number of SMS units being sent |
Mapping and Description of status codes
Detailed Status Code |
Nature of Detailed Status Code |
Status |
DetailedStatus |
What it means |
21010 |
Intermediate, may change in future |
queued |
PENDING_TO_OPERATOR |
The message is is being processed by Exotel. |
21015 |
Intermediate, may change in future |
sending |
SENDING_TO_OPERATOR |
The message has been processed by Exotel and is en-route to the operator. |
21020 |
Intermediate, may change in future |
submitted |
PENDING_ON_OPERATOR |
The 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 (10AM to 9PM). |
20005 |
Final |
sent |
DELIVERED_TO_HANDSET |
We know with confidence that the message has been delivered to recipient's handset. |
20006 |
Final |
sent |
DELIVERED_TO_OPERATOR |
The 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. |
23005 |
Final |
failed-dnd |
FAILED_REJECTED_DND |
The message has been rejected as the end user is a subscriber of DND (Do Not Disturb) services. |
23010 |
Final |
failed |
FAILED_INVALID_DESTINATION_NUMBER |
The destination number is incorrect, not SMS-enabled or is a PSTN landline. |
23015 |
Final |
failed |
FAILED_SPAM_DETECTED |
One 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. |
23020 |
Final |
failed |
FAILED_REJECTED_BLACKLIST |
You 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. |
24990 |
Final |
failed |
FAILED_UNKNOWN_ERROR |
Delivering 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. |
23030 |
Final |
failed |
FAILED_UNAVAILABLE_ROUTE |
The carrier and fallback carriers were not able to deliver the SMS message because no route was available. |
23035 |
Final |
failed |
FAILED_SUBSCRIBER_UNAVAILABLE |
This 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. |
23040 |
Final |
failed |
FAILED_SUBSCRIBER_UNKNOWN |
Subscriber is unknown to the operators or no longer active. |
23050 |
Final |
failed |
FAILED_EXPIRED |
The 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. |
23060 |
Final |
failed |
FAILED_REJECTED |
For a number of reasons, the message was rejected by Exotel or the operator. |
24105 |
Final |
failed |
FAILED_HANDSET_ERROR |
The message was not delivered to the subscriber due to handset failure |
24110 |
Final |
failed |
FAILED_OPERATOR_ERROR |
The message failed due to an issue at the operator end |
23070 |
Final |
failed |
FAILED_INVALID_MESSAGE |
The 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 unidentified character, may also fall under this bucket. |
23072 |
Final |
failed |
FAILED_INVALID_SENDER_ID
|
The message failed due to invalid or unregistered Sender ID. In case of India, if your Sender ID (header) is not registered with operator DLT platform, you may receive this error. |
24010 |
Final |
failed |
FAILED_SYSTEM_ERROR |
SMS failed while processing within Exotel system. |
24120 |
Final |
failed |
FAILED_SUBSCRIBER_ERROR |
All subscriber or recipient 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. |
23080 |
Final |
failed |
SENDER_BLOCKED_BY_DLT |
Applicable only for SMS sent to Indian destination numbers via domestic lines. Sender ID (Header) is blocked or failed at DLT platform by the operator due to mismatch, non-registration, template not linked with Sender (header) etc. |
23081 |
Final |
failed |
ENTITY_BLOCKED_BY_DLT |
Applicable only for SMS sent to Indian destination numbers via domestic lines. Entity (DLT Entity ID) is blocked or failed at DLT platform by the operator due to DLT Entity ID not passed in API or configured on Exotel Dashboard, values are mismatching etc. |
23082 |
Final |
failed |
TEMPLATE_BLOCKED_BY_DLT |
Applicable only for SMS sent to Indian destination numbers via domestic lines. Template (Template ID) is blocked or failed at DLT due to Template ID not set in API or configured on Exotel Dashboard, content is not exactly matching, non-registration of the template etc. |
23083 |
Final |
failed |
FAILED_DLT_SCRUBBING_ERROR |
Applicable only for SMS sent to Indian destination numbers via domestic lines. SMS is blocked or failed at DLT even after registration due to explicit blocking of the Sender ID due to spam, issues with consent or any other technical issues with DLT platform. |
23084 |
Final |
failed |
FAILED_DLT_CONSENT_ERROR |
SMS DLT consent registration is required for you to continue sending SMS to your customers. Applicable only for SMS sent to Indian destination numbers via domestic lines. |
23181 |
Final |
failed |
DLT_TEMPLATE_ID_INVALID |
Applicable only for SMS sent to Indian destination numbers via domestic lines. This Template is invalid. Some operators may report this error as 23182: DLT_TEMPLATE_NOT_FOUND. |
23182 |
Final |
failed |
DLT_TEMPLATE_NOT_FOUND |
Applicable only for SMS sent to Indian destination numbers via domestic lines. This Template was not found. |
23183 |
Final |
failed |
DLT_TEMPLATE_ID_INACTIVE |
Applicable only for SMS sent to Indian destination numbers via domestic lines. This Template is inactive. |
23184 |
Final |
failed |
DLT_TEMPLATE_ID_BLACKLISTED |
Applicable only for SMS sent to Indian destination numbers via domestic lines. This Template has been blacklisted. This may happen due to users reporting this message. |
23185 |
Final |
failed |
DLT_TEMPLATE_DOES_NOT_MATCH |
Applicable only for SMS sent to Indian destination numbers via domestic lines. The message body does not match the Template on the DLT portal. |
23186 |
Final |
failed |
DLT_LENGTH_EXCEEDED |
Applicable only for SMS sent to Indian destination numbers via domestic lines. The message has exceeded the maximum allowed length of 2000 characters. Some operators may report this error as 23185: DLT_TEMPLATE_DOES_NOT_MATCH. |
23281
|
Final |
failed |
DLT_ENTITY_NOT_FOUND |
Applicable only for SMS sent to Indian destination numbers via domestic lines. The ENTITY_ID was not found on the DLT portal. Some operators may report this error as 23081: ENTITY_BLOCKED_BY DLT. |
In case your SMS body contains special characters (like -, &, % etc), URL-encode the text
In case EncodingType is not set, then it will auto detect the encoding type of SMS, whether it is plain or unicode
DetailedStatusCode in the range of 23084-24000 are reserved for future and can be expanded for any other detailed status scenario related to SMS.
Mapping and Description of HTTP API Error Codes in the API response
POST (/send, /bulksend) API error codes:
Scenario |
HTTP Error Code |
API Error code |
Error message |
If your trial account is being used to send promotional SMS |
403 |
40000 |
Not allowed to send promotional SMS(s). |
If account is trial and KYC not completed, and one of the following occurs: - Number not whitelisted - It is whitelisted but is not of type agent-whitelist |
403 |
340030 |
Your account is not yet KYC compliant; |
If there is insufficient balance in your account |
403 |
40001 |
Insufficient balance to send $n sms. Please recharge your account. |
If account is not configured to send SMSes to the recipient country. |
403 |
40003 |
Your account is not configured to send SMSes to this country. Please write to hello@exotel.com to update the setup. |
If yours is a trial account with incomplete KYC and has a whitelisting error. Email hello@exotel.com for more details. |
500 |
35000 |
Internal Server Error |
Exotel internal error code related to processing. Email hello@exotel.com for more details. |
500 |
40100 |
Error Processing Request |
Message body for single send is invalid on account of it being empty/missing |
400 |
40200 |
Message body cannot be empty. |
Message body for bulk send is invalid on account of it being empty/missing |
400 |
40201 |
Invalid parameters: Messages is a mandatory field |
Invalid (Array) message body |
400 |
40202 |
Message body is invalid. |
If all destination numbers are invalid |
400 |
40203 |
All the destination numbers are invalid: $number |
Invalid SMS type parameter in request |
400 |
40204 |
Invalid parameters: SmsType is not set correctly |
Invalid (Empty) From parameter in request |
400 |
40205 |
Empty From field in the request |
From parameter does not match SMS type |
400 |
40206 |
Invalid parameters: From format is not matching with the SmsType |
Request parameter passed as array and not as a string |
400 |
40207 |
Array passed as Value in params. Expecting String |
Invalid (Non-array) messages parameter |
400 |
40208 |
Invalid parameters: Messages has to be an array |
Invalid encoding type parameter in SMS request |
400 |
40209 |
Encoding type is not properly set. Please check the encoding type again before sending the request for Msg=[$body] |
Missing FROM parameter in SMS request |
400 |
40210 |
Invalid parameters: From is a mandatory field |
If all the below conditions are true: - SMS type is promotional - It is an Indian account - Promotional sender ID is not found (contact hello@exotel.com) |
400 |
40300 |
No transactional template found and no numeric sender ID exists in your account for sending it as promotional |
If your sender ID is not found This is specific to international accounts and SMS type is not promotional |
400 |
40301 |
No transactional sender ID found in your account |
More than 100 SMSs in a dynamic bulk request |
400 |
40400 |
Not more than 100 SMSs are allowed in one API request. |
If your account has sent POST requests higher than the maximum limit feasible |
429 |
40402 |
Too many POST requests. |
In the trial phase, if your account exceeds the max. SMS limit |
429 |
40404 |
Please note that you can send only 10 SMS from your account during the trial phase. |
Throttle limit has been exceeded (Update to existing error code) |
503 |
35006 -> 40405 |
Service Unavailable |
More than 100 SMSs in a static bulk request |
400 |
40406 |
Not more than 100 SMSs are allowed in one API request. |
POST API call to an unrecognized SMS endpoint. eg: v1/Accounts/<account-sid>/Sms/<invalid-parameter> |
405 |
40502 |
This method is not supported |
POST (/send, /bulksend) and /GET (/sms) error codes:
Scenario |
HTTP Error Code |
API Error code |
Error message |
If your account is inactive |
403 |
40002 |
Account inactive. |
Api call to v1/Accounts/exotel42us3/Sms |
400 |
40500 |
Invalid Parameters |
Unsupported API version |
400 |
Exotel API Version $version not supported. Contact Exotel for details. |
|
Accounts missing from URL |
400 |
/Accounts/ missing from URL |
|
Account sid missing from URL |
403 |
34009 |
Action forbidden on given resource; |
Auth key or auth token missing |
401 |
Authentication is required to view this page. |
|
Invalid auth key or auth token |
401 |
34010 |
Unauthorized; |
Invalid Account sid or any resource or action is missing or invalid |
403 |
34009 |
Action forbidden on given resource; |
Non alpha-numeric auth key or token |
400 |
34001 |
Bad or missing parameters in request.; |