01 · How it works, in 6 steps
How does SMS OTP work?
- 1
Register the template on DLT
Register wording such as "{#var#} is your OTP to log in to YourApp. It is valid for {#var#} minutes. Do not share it with anyone." under your header, in the right category, and note the template ID you must send with each message.
- 2
Generate and store the code safely
Draw six digits from a cryptographically secure random source, store only a hash with the phone number, purpose, expiry (typically 5 to 10 minutes) and an attempt counter, and never log the plain code.
- 3
Write a single-segment message
Use only GSM-7 characters, put the code first, and keep the whole text under 140 bytes with the app hash on the last line if your Android app uses the SMS Retriever API.
- 4
Send with limits
Throttle requests per phone number, IP address, device and session, block countries you do not serve, and add a resend cooldown of 30 to 60 seconds before offering a voice or WhatsApp alternative.
- 5
Verify once, then expire
Compare in constant time, allow three to five attempts, delete the code on success or expiry, and bind the verified number to the session that asked for it.
- 6
Measure conversion, not sends
Track codes verified divided by codes sent, per country and operator, plus time from send to delivery report. A sudden drop in conversion is the earliest sign of pumping or a broken route.
02Try it
Hands-on: use the controls to work through it yourself.
Will your OTP fit in one SMS?
Encoding
UCS-2
16-bit Unicode · 70 per SMS, 67 per part
Characters
114
114 UTF-16 units
SMS parts
2
67 per part
Left in part
20
before part 3
Billed as 2 SMS
Part 167 / 67
482913 आपका YourApp लॉगिन OTP है। यह 5 मिनट तक मान्य है। इसे किसी क
Part 247 / 67
े साथ साझा न करें, हमारे स्टाफ़ के साथ भी नहीं।
Header (UDH) — 3 units of every part go to reassembly data.
How it splits
- Alternating parts
- Forces UCS-2
Why
“आ”, “प”, “क” and 25 more are not in the GSM-7 alphabet, so the whole message is sent as UCS-2: one SMS holds 70 characters instead of 160. At 114 units it goes as 2 parts of up to 67 — each part gives 3 units to the header that stitches them together.
- आ (U+0906)
- प (U+092A)
- क (U+0915)
- ा (U+093E)
- ल (U+0932)
- ॉ (U+0949)
- ग (U+0917)
- ि (U+093F)
- +20 more
Hindi wording: UCS-2, 2 SMS parts.
03What is SMS OTP?
SMS OTP (SMS one-time password, or one-time passcode) is a short code, usually six digits, that a server generates, sends to a phone number by text message and asks the user to type back. Matching codes prove the person controls that number at that moment. It is the oldest and most universal phone verification method: it works on every handset, needs no app or mobile data, and every SMS gateway supports it.
In India an OTP is commercial SMS, so it travels under the DLT regime. The business is registered as a principal entity, sends from a registered header, and the wording must match a registered DLT content template in which the code (and any other value) is a {#var#} placeholder. OTPs are normally registered in the transactional category, for banks' transaction codes, or as service-implicit messages, for logins and verifications by other businesses. Wording that drifts from the registered template is rejected at DLT scrubbing before it reaches the phone.
A good OTP SMS is short and boring: the code first, what it is for, how long it is valid, a warning not to share it and, for Android apps, the 11-character app hash that lets Google's SMS Retriever API read the code automatically. It should fit one segment: 160 GSM-7 characters, or only 70 once a single UCS-2 character slips in. The weaknesses are well known. SIM swap fraud and signalling attacks can redirect codes, congested routes can deliver them late, and bots abuse open send endpoints for SMS pumping, also called artificially inflated traffic (AIT). That is why many teams now try a WhatsApp authentication template, silent network authentication or flash call verification first and keep SMS OTP as the fallback that reaches everyone.
Key takeaways
- SMS OTP sends a short, random, single-use code by text message to prove a user controls a phone number.
- In India an OTP is commercial SMS: it needs a DLT header and a registered content template with
{#var#}for the code. - Keep the text to one GSM-7 segment; one emoji or curly quote switches it to UCS-2 and can double the cost.
- Android apps can read the code without SMS permission if the text is under 140 bytes and ends with the app's 11-character hash.
- Rate-limit every send endpoint: SMS OTP is the main target of SMS pumping fraud, and SIM swap can redirect codes.
04 · In code
SMS OTP in code
import crypto from "node:crypto";const TTL_SECONDS = 300; // 5-minute validityconst MAX_ATTEMPTS = 5;const hash = (code, phone) =>crypto.createHmac("sha256", process.env.OTP_PEPPER).update(phone + ":" + code).digest("hex");export async function sendOtp(phone) {const code = crypto.randomInt(0, 1_000_000).toString().padStart(6, "0");await redis.set(`otp:${phone}`, JSON.stringify({ h: hash(code, phone), tries: 0 }), "EX", TTL_SECONDS);await smsGateway.send({to: phone,sender: process.env.DLT_HEADER,templateId: process.env.DLT_OTP_TEMPLATE_ID, // must match the registered wordingtext: `${code} is your OTP to log in to YourApp. It is valid for 5 minutes. Do not share it with anyone.\n${process.env.ANDROID_APP_HASH}`,});}export async function verifyOtp(phone, code) {const raw = await redis.get(`otp:${phone}`);if (!raw) return false; // expired or never sentconst rec = JSON.parse(raw);if (rec.tries >= MAX_ATTEMPTS) return false;rec.tries += 1;await redis.set(`otp:${phone}`, JSON.stringify(rec), "KEEPTTL");const ok = crypto.timingSafeEqual(Buffer.from(rec.h), Buffer.from(hash(code, phone)));if (ok) await redis.del(`otp:${phone}`); // single usereturn ok;}
Store a keyed hash, never the code; count attempts; delete on success. `smsGateway.send` stands in for your provider's client.
05 · Mistakes to avoid
Common mistakes with SMS OTP
Unicode in the wording
A Hindi sentence, an emoji or a curly apostrophe pasted from a document switches the message to UCS-2, cuts the limit to 70 characters and pushes the code over two segments. Keep OTP text in plain GSM-7 and localise the screen instead.
An open send endpoint
Without per-number, per-IP and per-country limits, bots can trigger thousands of OTPs to premium ranges and leave you with the bill. Rate-limit, block countries you do not serve and watch the conversion rate.
Long validity and unlimited attempts
A six-digit code with no attempt limit can be brute-forced. Expire codes in minutes, cap attempts per code and per number, and invalidate older codes when a new one is sent.
Template drift
Changing a word in the app without registering a matching DLT template makes operators reject every OTP. Treat the template text as a contract and test it after every release.
Using SMS as the only factor for risky actions
SIM swap fraud lets an attacker receive the victim's SMS. For payouts, password resets or device changes, add a SIM-change check, device binding or a second factor.
06Example: A Lucknow edtech app halves its OTP bill
A Lucknow test-prep app sends its login OTP in Hindi, about 95 characters of Devanagari, so every code goes as two UCS-2 segments, and its Android autofill never fires because the text is over 140 bytes. The team registers a new English DLT template of 98 GSM-7 characters with the app hash on the last line, keeps a Hindi screen in the app itself, and adds a 45-second resend cooldown. Each OTP now costs one segment, autofill fills the code on most Android phones, and verified logins per OTP sent rise from 71% to 84%.
07 · Key facts
SMS OTP: key facts and limits
- Typical code
- 6 digits (1,000,000 possible values)
- Typical validity
- 5 to 10 minutes, single use
- One SMS holds
- 160 GSM-7 or 70 UCS-2 characters
- Android autofill
- ≤ 140 bytes, code plus 11-character app hash
- India requirement
- DLT header and content template with {#var#}
- Usual DLT category
- Transactional (bank OTPs) or service-implicit
08 · Why it matters
Why does SMS OTP matter?
Verification sits on the most valuable path in most apps: sign-up, login, payment and password reset. If the code is late, garbled or blocked, users abandon at the exact moment they meant to convert, and every resend adds cost. Getting the template, the wording, the segment count and the abuse controls right is cheap engineering that protects conversion, the SMS bill and the user's account at once.
09 · Pro tips
Best practices for SMS OTP
- Put the code at the very start of the message so it shows in the notification preview.
- Never include links in OTP texts; they confuse users, and unregistered URLs are blocked on DLT anyway.
- Show the number you sent to and a visible countdown before the resend button activates.
- Offer voice or WhatsApp as the second attempt rather than a third SMS.
10SMS OTP FAQs
Is SMS OTP secure enough?+
Why is my OTP SMS not delivered in India?+
What is the 11-character code at the end of some OTP messages?+
Is a WhatsApp OTP cheaper than an SMS OTP?+
* Per-message rates for India, ex-GST: marketing, utility and authentication effective 1 July 2026; service messages ₹0.145 since 1 October 2026 (they were ₹0 until 30 September 2026). Volume commitments earn discounts — final rate is confirmed on your account; applicable GST extra. Rates for other countries differ (see the international rate table on /pricing).