Skip to content

Playbook · 6 steps

SMS OTP

Also called: SMS one-time password · OTP SMS · SMS verification code · Text message OTP

6steps

Level
Foundation
Reading time
About 6 min

Reviewed

Definition
A one-time passcode sent by text message to verify a user, simple and universal but exposed to SIM swaps, delivery delays and SMS pumping fraud.

01 · How it works, in 6 steps

How does SMS OTP work?

  1. 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. 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. 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. 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. 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. 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?

4 / 4

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

Part 1482913 आपका YourApp लॉगिन OTP है। यह 5 मिनट तक मान्य है। इसे किसी कPart 2े साथ साझा न करें, हमारे स्टाफ़ के साथ भी नहीं।
  • 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
Pick a sample OTP or type your own. The counter shows the encoding and how many billed parts the text needs, and highlights the characters that force UCS-2.

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 validity
const 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 wording
text: `${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 sent
const 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 use
return 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?+
For low- and medium-risk verification, usually yes; for high-value actions, not on its own. SMS can be redirected through SIM swap fraud or signalling attacks and read on lock screens, so pair it with device binding, a SIM-change check or a stronger factor where a takeover would be costly.
Why is my OTP SMS not delivered in India?+
The most common cause is a DLT mismatch: wording, header or category that does not match the registered template, so scrubbing rejects it. Check the delivery report's state and error code; switched-off phones, ported numbers and congested routes explain most of the rest.
What is the 11-character code at the end of some OTP messages?+
It is an app hash for Android's SMS Retriever API. It tells the phone which app the code belongs to, so that app can read the OTP automatically without asking for permission to read all SMS.
Is a WhatsApp OTP cheaper than an SMS OTP?+
It depends on your SMS contract and fallback design. A WhatsApp authentication template is billed per delivered message at ₹0.14 in India, while SMS is billed per segment and often per submission; the WhatsApp vs SMS OTP cost page works through cost per verified login.

See InfiQ pricing

* 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).

From definition to your first message

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.