Send Your First SMS
Send your first SMS with Exotel in under 5 minutes. This guide walks you through getting your API credentials and making your first API call.
Prerequisites
Before you begin, make sure you have:
- An Exotel account (Sign up here)
- API credentials (API Key, API Token, Account SID)
- For India: DLT registration (Entity ID and Template ID)
Log in to the Exotel Dashboard → Settings → API Settings. You'll find your API Key, API Token, and Account SID on this page. See Authentication for details.
Step 1: Set Up Your Credentials
Store your credentials as environment variables to keep them out of your code:
- macOS / Linux
- Windows
export EXOTEL_API_KEY="your_api_key"
export EXOTEL_API_TOKEN="your_api_token"
export EXOTEL_ACCOUNT_SID="your_account_sid"
export EXOTEL_SUBDOMAIN="api.exotel.com"
set EXOTEL_API_KEY=your_api_key
set EXOTEL_API_TOKEN=your_api_token
set EXOTEL_ACCOUNT_SID=your_account_sid
set EXOTEL_SUBDOMAIN=api.exotel.com
Use api.exotel.com (Singapore) for most accounts, or api.in.exotel.com (Mumbai) for India-based accounts with lower latency needs.
Step 2: Send Your First SMS
- cURL
- Python
- Node.js
- PHP
- Go
curl -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" -X POST \
"https://$EXOTEL_SUBDOMAIN/v1/Accounts/$EXOTEL_ACCOUNT_SID/Sms/send" \
-d "From=EXOTEL" \
-d "To=+919876543210" \
-d "Body=Hello from Exotel! Your OTP is 123456" \
-d "DltEntityId=YOUR_DLT_ENTITY_ID" \
-d "DltTemplateId=YOUR_DLT_TEMPLATE_ID"
# send_sms.py
import os
import requests
api_key = os.environ['EXOTEL_API_KEY']
api_token = os.environ['EXOTEL_API_TOKEN']
account_sid = os.environ['EXOTEL_ACCOUNT_SID']
subdomain = os.environ.get('EXOTEL_SUBDOMAIN', 'api.exotel.com')
url = f'https://{subdomain}/v1/Accounts/{account_sid}/Sms/send'
data = {
'From': 'EXOTEL',
'To': '+919876543210',
'Body': 'Hello from Exotel! Your OTP is 123456',
'DltEntityId': 'YOUR_DLT_ENTITY_ID',
'DltTemplateId': 'YOUR_DLT_TEMPLATE_ID',
}
response = requests.post(url, data=data, auth=(api_key, api_token))
if response.ok:
result = response.json()
print('SMS sent successfully!')
print('SMS SID:', result['SMSMessage']['Sid'])
print('Status:', result['SMSMessage']['Status'])
else:
print('Failed:', response.text)
Run with:
pip install requests
python send_sms.py
// send-sms.js — Requires Node.js 18+
const apiKey = process.env.EXOTEL_API_KEY;
const apiToken = process.env.EXOTEL_API_TOKEN;
const accountSid = process.env.EXOTEL_ACCOUNT_SID;
const subdomain = process.env.EXOTEL_SUBDOMAIN || 'api.exotel.com';
async function sendSMS() {
const url = `https://${subdomain}/v1/Accounts/${accountSid}/Sms/send`;
const params = new URLSearchParams({
From: 'EXOTEL',
To: '+919876543210',
Body: 'Hello from Exotel! Your OTP is 123456',
DltEntityId: 'YOUR_DLT_ENTITY_ID',
DltTemplateId: 'YOUR_DLT_TEMPLATE_ID',
});
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from(`${apiKey}:${apiToken}`).toString('base64'),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
const data = await response.json();
if (response.ok) {
console.log('SMS sent successfully!');
console.log('SMS SID:', data.SMSMessage.Sid);
console.log('Status:', data.SMSMessage.Status);
} else {
console.error('Failed:', data);
}
} catch (error) {
console.error('Error:', error.message);
}
}
sendSMS();
Run with:
node send-sms.js
<?php
$apiKey = getenv('EXOTEL_API_KEY');
$apiToken = getenv('EXOTEL_API_TOKEN');
$accountSid = getenv('EXOTEL_ACCOUNT_SID');
$subdomain = getenv('EXOTEL_SUBDOMAIN') ?: 'api.exotel.com';
$data = array(
'From' => 'EXOTEL',
'To' => '+919876543210',
'Body' => 'Hello from Exotel! Your OTP is 123456',
'DltEntityId' => 'YOUR_DLT_ENTITY_ID',
'DltTemplateId' => 'YOUR_DLT_TEMPLATE_ID',
);
$ch = curl_init("https://{$subdomain}/v1/Accounts/{$accountSid}/Sms/send");
curl_setopt($ch, CURLOPT_USERPWD, "{$apiKey}:{$apiToken}");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
)
func main() {
apiKey := os.Getenv("EXOTEL_API_KEY")
apiToken := os.Getenv("EXOTEL_API_TOKEN")
accountSid := os.Getenv("EXOTEL_ACCOUNT_SID")
subdomain := os.Getenv("EXOTEL_SUBDOMAIN")
if subdomain == "" {
subdomain = "api.exotel.com"
}
endpoint := fmt.Sprintf("https://%s/v1/Accounts/%s/Sms/send", subdomain, accountSid)
data := url.Values{}
data.Set("From", "EXOTEL")
data.Set("To", "+919876543210")
data.Set("Body", "Hello from Exotel! Your OTP is 123456")
data.Set("DltEntityId", "YOUR_DLT_ENTITY_ID")
data.Set("DltTemplateId", "YOUR_DLT_TEMPLATE_ID")
req, _ := http.NewRequest("POST", endpoint, strings.NewReader(data.Encode()))
req.SetBasicAuth(apiKey, apiToken)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
}
Step 3: Check the Response
A successful request returns:
{
"SMSMessage": {
"Sid": "a]1b2c3d4e5f6",
"AccountSid": "your_sid",
"From": "EXOTEL",
"To": "+919876543210",
"Body": "Hello from Exotel! Your OTP is 123456",
"Status": "queued",
"DateCreated": "2026-02-25 10:30:00",
"DateSent": null,
"Price": null
}
}
| Field | What it means |
|---|---|
Sid | Your unique SMS ID — save this to check delivery later |
Status | queued means accepted and waiting to be sent |
Price | Updates after delivery |
A 200 response means the SMS was accepted, not delivered. The Status will be queued. Use the SMS Details endpoint or set up a StatusCallback webhook to track delivery.
Step 4: Verify Delivery (Optional)
Check if your SMS was delivered using the Sid from Step 3:
curl -u "$EXOTEL_API_KEY:$EXOTEL_API_TOKEN" \
"https://$EXOTEL_SUBDOMAIN/v1/Accounts/$EXOTEL_ACCOUNT_SID/SMS/Messages/YOUR_SMS_SID.json"
Look for "DetailedStatus": "DELIVERED_TO_HANDSET" in the response.
Understanding DLT (India)
DLT (Distributed Ledger Technology) is a regulatory requirement by TRAI for all SMS sent in India. You need:
- DLT Entity ID — Register as a business entity on a DLT portal (e.g., Jio, Airtel, Vodafone-Idea)
- DLT Template ID — Register your message templates for approval
- Sender ID — Register your header/sender ID (e.g., "EXOTEL")
Without DLT registration, SMS to Indian numbers will be blocked by telecom operators.
What's Next?
- Send SMS — Full API Reference — All parameters, response fields, and error codes
- Bulk SMS — Send to Multiple Numbers — Send up to 100 messages per request
- SMS Delivery Status Codes — Understand delivery statuses
- Webhooks — Get Delivery Notifications — Real-time delivery updates
- Error Codes Reference — Troubleshoot common errors