Tutorials

OTP SMS Deliverability Checklist for Production Apps

Production checklist to improve OTP delivery rates in India. Covers E.164 formatting, DLT template matching, TRAI scrubbing, retries, and monitoring.

StartMessaging Team Updated

Poor OTP deliverability shows up as login failures, abandoned carts, and angry support tickets. When a user taps “Send OTP” and nothing arrives within 10 seconds, they leave — and most do not come back. The frustrating part is that many delivery failures are not carrier issues or network problems. They are preventable bugs in how your app formats numbers, matches DLT templates, handles retries, and monitors delivery health.

This checklist covers the specific technical steps Indian developers should implement before blaming carriers or switching SMS providers. Each item addresses a real failure mode that causes OTP non-delivery in production, with the fix that resolves it.

Checklist 1: Clean Phone Number Formatting

Phone number formatting errors are the most common cause of silent OTP failures — the SMS API accepts the request, returns a success response, but the message never arrives because the number is malformed at the carrier level.

Normalize Every Number to E.164

E.164 is the international phone number format: a + sign followed by the country code and national number with no spaces, dashes, or parentheses. For India, the correct format is +91 followed by exactly 10 digits. No leading zero in the national portion.

Valid Indian E.164 numbers:

  • +919876543210 — correct
  • +91 9876543210 — incorrect (space after country code)
  • 919876543210 — incorrect (missing + prefix)
  • +910987654321 — incorrect (leading zero in national number)
  • 09876543210 — incorrect (local format with trunk prefix)

Implement E.164 validation at the point of phone number entry in your app, not at send time. Rejecting or auto-correcting invalid numbers during signup prevents delivery failures downstream.

function normalizeIndianPhone(input) {
  // Strip all non-digit characters
  const digits = input.replace(/\D/g, '');

  // Handle common Indian formats
  if (digits.length === 10) return `+91${digits}`;
  if (digits.length === 12 && digits.startsWith('91')) return `+${digits}`;
  if (digits.length === 11 && digits.startsWith('0')) return `+91${digits.slice(1)}`;

  return null; // Invalid — reject at signup
}

Validate Before Sending

Beyond format, verify that the number is a mobile number (not a landline). Indian mobile numbers start with 6, 7, 8, or 9 after the country code. A number starting with +91-2 or +91-1 is a landline and cannot receive SMS. Our API documentation describes the expected phone format and returns clear error codes for invalid numbers.

Handle International Numbers

If your app accepts non-Indian numbers, maintain per-country validation rules. Each country has different number lengths and valid prefixes. Using a library like libphonenumber (Google’s open-source phone number parser) is the most reliable approach. Do not build custom regex patterns for every country — the edge cases are extensive.

Checklist 2: DLT Template and Message Content Alignment

On Indian routes, your OTP message body must match an approved DLT template character for character, with variable substitution being the only allowed difference. The TRAI scrubbing engine compares each outbound SMS against registered templates in real time. Messages that do not match an approved template are blocked at the operator level — the user never receives them.

Common Template Mismatch Failures

  • Extra whitespace: Your API sends “Your OTP is 1234 ” (trailing space) but the template is “Your OTP is {#var#}” (no trailing space). The extra space causes a mismatch and the message is blocked.
  • Missing brand signature: Your template ends with ”- YourBrand” but your API does not append the brand name. The missing signature causes a mismatch.
  • Line break differences: Your template uses \n for line breaks but your API sends \r\n (Windows-style line breaks). Different line break characters cause comparison failures.
  • Character encoding: Your template uses Unicode characters (like ₹ or —) but your SMS is encoded in GSM-7. Characters outside the GSM-7 character set are either dropped or replaced, causing template mismatches.

Test Template Matching in Staging

Before going to production, send test messages with your actual DLT template and verify delivery on real SIMs across Jio, Airtel, Vi, and BSNL. Do not rely on sandbox environments alone — real carrier scrubbing behaviour can differ from sandbox simulation. If you use a managed service like StartMessaging, DLT template matching is handled automatically because our infrastructure uses pre-approved templates that are guaranteed to pass scrubbing.

Avoid Content That Triggers Scrubbing

Even with a valid template, certain content patterns in your dynamic variables can trigger additional scrubbing. Avoid placing URLs, phone numbers, or anything that looks like promotional content inside your OTP variable values. The variable should contain only the OTP code and basic metadata (app name, expiry time). Keep variables clean and predictable.

Checklist 3: Timing, Expiry, and User Experience

OTP delivery failures are not always technical — sometimes the message arrives but the user experience around it causes the verification to fail. Codes that expire too quickly, UIs that do not explain what to expect, and resend buttons that trigger too soon all contribute to perceived delivery failures.

Set Realistic Expiry Times

OTP codes that expire in under 2 minutes cause unnecessary failures on congested networks. During peak hours (9–11 AM, 7–9 PM IST), carrier networks in tier-2 and tier-3 cities can take 8–15 seconds for SMS delivery. Add DLT scrubbing latency (1–3 seconds) and handset processing time, and a 60-second expiry is dangerously tight.

Recommended expiry settings:

  • Minimum: 2 minutes (120 seconds)
  • Recommended: 5 minutes (300 seconds)
  • Maximum: 10 minutes (600 seconds) — beyond this, the security benefit of a time-limited code diminishes

Read our detailed guide on OTP expiry and attempt limits for balanced defaults based on risk level.

Show Clear UI Copy

When the user taps “Send OTP,” your UI should immediately:

  1. Show a message confirming that an SMS is being sent to the displayed phone number (mask the middle digits for privacy: +91 98****3210)
  2. Display a visible countdown timer before the resend button becomes active (30–60 seconds recommended)
  3. Support paste from SMS where the platform allows it — on Android, use the SMS Retriever API for zero-touch autofill

Users who see clear feedback (“SMS sent — arriving in a few seconds”) are significantly less likely to file support tickets or abandon the flow compared to users who see no feedback and a greyed-out screen.

Rate-Limit Resend Requests

Expose a resend button only after a cooldown period. Implementing escalating cooldowns (30 seconds for first resend, 60 seconds for second, 120 seconds for third) prevents both user frustration and SMS pumping attacks. After 3–5 failed attempts on the same number, block further OTP requests for that number for 15–30 minutes.

Checklist 4: Retries, Failover, and Provider Resilience

Automatic retries sound helpful in theory, but blind retries can duplicate messages, violate rate limits, and create a worse experience than a single failed delivery. Implement retries carefully with explicit rules.

Retry Rules

  • Do not retry on user-initiated resend. When the user taps “Resend OTP,” generate a new code, invalidate the old one, and send a fresh message. Do not replay the original API call.
  • Do retry on transient provider errors. If your SMS API returns a 5xx error or a timeout, retry once with exponential backoff (wait 2 seconds, then 4 seconds). Do not retry more than twice — if the provider is down, a third attempt will not help.
  • Do not retry on hard errors. If the API returns a 4xx error (invalid number, blocked number, insufficient balance), retrying is pointless. Log the error and surface it to the user as an appropriate message.

Multi-Provider Failover

If your product sends high volumes (50,000+ OTPs/month), configure a secondary SMS provider as failover. The architecture is straightforward: attempt delivery through Provider A, and if Provider A returns a failure or does not deliver within your SLA (typically 5–10 seconds), automatically retry through Provider B with the same OTP code.

Prefer providers that offer transparent delivery status codes so you can distinguish between soft failures (temporary carrier congestion) and hard failures (invalid number, DND-blocked number). StartMessaging’s API provides detailed delivery status callbacks and handles multi-carrier failover internally, so you get built-in resilience without managing multiple provider integrations.

Checklist 5: What to Measure and Monitor

You cannot improve OTP deliverability without measuring it. At minimum, track these five metrics and set up alerts for anomalies.

Core Metrics

MetricWhat it tells youAlert threshold
Send acceptance rate% of API calls that return successBelow 98% — investigate API errors
Delivery success rate% of sent messages confirmed deliveredBelow 95% — investigate carrier issues
Time-to-deliver (P50/P95)How long messages take to reach the userP95 above 10 seconds — investigate routing
Verify success rate% of delivered OTPs that are correctly enteredBelow 85% — investigate UX or expiry issues
Cost per successful verificationTotal SMS cost ÷ successful verificationsRising trend — investigate retry waste

Slice by Carrier and Region

If your SMS provider exposes carrier-level delivery data, slice your metrics by carrier (Jio, Airtel, Vi, BSNL) and by region (metro, tier-2, tier-3). Delivery issues are often carrier-specific or region-specific — a national average of 96% delivery can mask a 70% delivery rate on BSNL in specific circles.

Vendor Comparison Methodology

When comparing SMS vendors, use the same traffic profile and the same time window. Sending 100 test messages on a Saturday afternoon and comparing the delivery rate to your production provider’s weekday metrics is not a valid comparison. Our OTP API pricing comparison for India explains how to compare total cost of verification (including failed deliveries and retries), not just per-SMS price.

Frequently Asked Questions

Q: Why is my OTP not being received on BSNL numbers in India?

A: BSNL has consistently lower SMS delivery rates than Jio, Airtel, and Vi, particularly in rural circles. Common causes include slower DLT scrubbing infrastructure, network congestion during peak hours, and outdated SMSC (Short Message Service Centre) hardware in certain circles. If you see a pattern of BSNL failures, consider adding voice OTP as a fallback for BSNL numbers specifically. StartMessaging’s multi-carrier routing automatically selects the optimal route for BSNL delivery.

Q: Should I use SMS Retriever API or request SMS permission for OTP autofill?

A: Use SMS Retriever API. Requesting READ_SMS permission is invasive, triggers Google Play policy reviews, and makes users uncomfortable. SMS Retriever requires no runtime permission — it listens for SMS messages containing a specific hash and auto-fills the OTP code without accessing the full SMS inbox. Read our SMS Retriever implementation guide for the step-by-step setup.

Q: What delivery rate should I expect for OTP SMS in India?

A: With a properly configured DLT-compliant setup, you should see 95–98% delivery rates on Jio and Airtel, 92–96% on Vi, and 85–93% on BSNL. If your rates are below these benchmarks, the issue is likely in your template matching, number formatting, or provider routing — not in the carrier network. Read our OTP delivery rate benchmarks for India for detailed carrier-by-carrier data.

Q: How does StartMessaging handle OTP deliverability automatically?

A: StartMessaging’s OTP API handles E.164 normalization, DLT template matching, multi-carrier routing, automatic retries on transient failures, and real-time delivery tracking — all at ₹0.25 per OTP. You send one API call with a phone number, and the platform handles number validation, template compliance, carrier selection, and delivery confirmation. Sign up free and test delivery on your own numbers.

S

StartMessaging Team

StartMessaging Team

Related posts