Integrating an OTP SMS API into your application in India involves more than a simple HTTP call — you need a registered DLT entity, an approved transactional template, and a gateway that prioritises delivery speed. This guide walks you through every step, from DLT onboarding to production-ready code.
Why OTP SMS Requires Special Handling in India
India's TRAI (Telecom Regulatory Authority of India) introduced the DLT (Distributed Ledger Technology) framework in 2021 to combat SMS spam and phishing. Every commercial SMS sender — including businesses sending OTPs — must register three things before a single message can be delivered:
- Entity registration — proves your business identity on the DLT portal
- Sender ID (Header) — the 6-character alphanumeric tag that appears as the sender name (e.g., GCMDIA)
- Message template — the exact text of your OTP message, with variable placeholders declared
Without these three registrations, telecom operators will scrub your messages before they reach recipients. This makes DLT registration the critical first step in any OTP SMS integration.
Step 1 — Complete DLT Registration
Choose a DLT Portal
TRAI has authorised multiple telecom operators to run DLT portals. Common options include:
- Jio Trueconnect — trueconnect.jio.com
- Airtel DLT — dltconnect.airtel.in
- Vi (Vodafone Idea) DLT — vilpower.in
- BSNL DLT — smsid.bsnl.co.in
Registration on any one portal is sufficient — your data is shared across all operators via the DLT blockchain.
Register Your Entity
Provide your business PAN, GST certificate (if applicable), and a valid address. Approval typically takes 1–3 business days.
Register Your Sender ID
A transactional sender ID is 6 characters (letters only). Example: GCMDIA. Register under the Transactional category.
Register Your OTP Template
Your template must match the exact format you will send. Variables are declared with curly braces. A typical OTP template:
Your {#var#} is the OTP for login to {#var#}. Valid for 10 minutes. Do not share it with anyone. — GCMDIA
Template approval by the telecom operator takes 1–3 business days.
Step 2 — Obtain API Credentials
Sign up with an OTP SMS provider (Get Click Media) and note your:
- API Key — used to authenticate every request
- Sender ID — your DLT-registered header
- Template ID — the DLT template ID assigned after approval
Step 3 — Send an OTP via the REST API
The API endpoint accepts a POST request with your recipient number, message, and authentication headers.
Node.js (fetch)
const sendOtp = async (mobile, otp) => {
const message = `Your ${otp} is the OTP for login. Valid for 10 minutes. Do not share it. — GCMDIA`;
const response = await fetch("https://api.getclickmedia.com/sms/send", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.GCM_API_KEY,
},
body: JSON.stringify({
to: mobile, // e.g. "919876543210"
message,
senderId: "GCMDIA",
templateId: process.env.GCM_TEMPLATE_ID,
type: "transactional",
}),
});
const data = await response.json();
return data; // { messageId: "...", status: "queued" }
};
Python (requests)
import os
import requests
def send_otp(mobile: str, otp: str) -> dict:
message = f"Your {otp} is the OTP for login. Valid for 10 minutes. Do not share it. — GCMDIA"
response = requests.post(
"https://api.getclickmedia.com/sms/send",
headers={
"Content-Type": "application/json",
"x-api-key": os.environ["GCM_API_KEY"],
},
json={
"to": mobile,
"message": message,
"senderId": "GCMDIA",
"templateId": os.environ["GCM_TEMPLATE_ID"],
"type": "transactional",
},
)
return response.json()
PHP (cURL)
function sendOtp(string $mobile, string $otp): array {
$message = "Your {$otp} is the OTP for login. Valid for 10 minutes. Do not share it. — GCMDIA";
$ch = curl_init("https://api.getclickmedia.com/sms/send");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: " . $_ENV["GCM_API_KEY"],
],
CURLOPT_POSTFIELDS => json_encode([
"to" => $mobile,
"message" => $message,
"senderId" => "GCMDIA",
"templateId" => $_ENV["GCM_TEMPLATE_ID"],
"type" => "transactional",
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
return $result;
}
Step 4 — Handle Delivery Reports via Webhooks
Rather than polling for delivery status, configure a webhook URL in your provider dashboard. The provider will POST a delivery receipt to your endpoint after each OTP is delivered or fails.
Example Webhook Payload
{
"messageId": "gcm_abc123",
"to": "919876543210",
"status": "delivered",
"deliveredAt": "2026-06-19T10:23:45Z",
"operator": "Jio"
}
Node.js Webhook Handler (Express)
app.post("/webhooks/sms-delivery", express.json(), (req, res) => {
const { messageId, to, status, deliveredAt } = req.body;
if (status === "failed") {
// Trigger a resend or alert your ops team
console.error(`OTP delivery failed for ${to} — messageId: ${messageId}`);
}
res.sendStatus(200);
});
Step 5 — OTP Generation Best Practices
The SMS API only handles delivery — your application is responsible for generating and validating the OTP. Follow these rules:
Generate a Cryptographically Secure OTP
Node.js:
import { randomInt } from "crypto";
const otp = randomInt(100000, 999999).toString();
Python:
import secrets
otp = str(secrets.randbelow(900000) + 100000)
Store with Expiry
Store the OTP hash (not plaintext) against the user's session with a short TTL:
import bcrypt from "bcrypt";
import redis from "./redis";
const hash = await bcrypt.hash(otp, 10);
await redis.set(`otp:${mobile}`, hash, { EX: 600 }); // 10-minute expiry
Rate-Limit Resend Requests
Prevent OTP bombing by limiting resend requests per mobile number:
const attempts = await redis.incr(`otp_attempts:${mobile}`);
if (attempts === 1) await redis.expire(`otp_attempts:${mobile}`, 3600);
if (attempts > 5) throw new Error("Too many OTP requests. Try again in an hour.");
Step 6 — Testing Before Go-Live
Before going live, verify:
- DLT entity, sender ID, and template are all in Approved state
- Test OTP reaches your number within 3 seconds
- Delivery webhook fires correctly for both delivered and failed status
- OTP expiry and rate-limiting logic is working
- Variable substitution in the template matches exactly — mismatches cause scrubbing
Common Integration Mistakes to Avoid
| Mistake | Impact |
|---|---|
| Sending before DLT template is approved | All messages scrubbed; zero delivery |
| Variable mismatch between code and template | Message blocked at operator |
| Storing OTP in plaintext | Security vulnerability |
| No rate limiting on resend | OTP bombing, inflated costs |
| Polling for delivery instead of webhooks | Delayed error detection, extra API calls |
Summary
Integrating an OTP SMS API in India requires DLT registration before the first API call, a cryptographically secure OTP generation strategy, and webhook-based delivery monitoring for production reliability. With Get Click Media's transactional SMS infrastructure, OTPs reach recipients in under 3 seconds across all Indian telecom operators — including DND-registered numbers.
Ready to get started? Request a free demo or view our OTP SMS pricing.
Frequently Asked Questions
An OTP SMS API is a REST or HTTP endpoint that allows developers to trigger one-time password delivery to any mobile number programmatically. You call the API from your backend with the recipient number and your message template; the provider routes the message through the transactional telecom network.
Yes. TRAI mandates that your entity, sender ID, and OTP message template be registered on a DLT portal before any transactional SMS can be sent. Without pre-approved templates, telecom operators scrub the message before delivery.
On a properly configured transactional route, OTP SMS delivery typically takes under 3 seconds under normal network conditions. Get Click Media uses priority carrier queues and automatic failover to maintain sub-second gateway dispatch.
Yes. OTP SMS travels via the transactional route, which is exempt from DND (Do Not Disturb) filtering under TRAI regulations. All registered users receive the OTP regardless of their DND status.




