Skip to content

    OTP SMS Delivery Best Practices in India

    One code, five hops from your server to a phone: who owns each one, what TRAI’s rules check there and what you can see. It makes no delivery-rate promise.

    Hops, Request To Verify
    5
    Longest Code Life, NIST
    10 min
    Digits Minimum, NIST
    6

    Checked against TRAI’s regulation, consolidated 21 May 2026, and NIST SP 800-63B-4

    • NotifyTech AI Team
    • 7 min read
    • Development

    What an OTP asks of the SMS path

    TRAI defines an OTP as an automatically generated random number used to authenticate the action of a user for a single transaction or session. Someone is waiting on a screen for it, so an OTP that arrives late is a login or payment that did not happen.

    This guide follows one code from your server to a phone in five hops, says who owns each hop and what TRAI requires there, and ends with a ledger of what to do and what to avoid. The registration steps themselves are in our TRAI DLT registration guide. This is not legal advice: check your DLT portal for your own account.

    An OTP at a glance

    Message type
    Transactional (-T): a reply to a customer-initiated transaction within 30 minutes
    Explicit consent
    Not required for a transactional message
    Sender
    A registered header; check its format on your DLT portal
    Links
    None needed. Any link must be whitelisted
    The code
    At least 6 digits, used once, invalid after 10 minutes

    What happens between your server and the phone?

    Five hops, in order: your request, the template check, the operator network, the handset and your verify step. You own the first and the last. For the three in between, what you can know is limited to what the delivery report tells you.

    1. Request

      Seen

    2. Template

      Seen

    3. Network

      Blind

    4. Handset

      Blind

    5. Verify

      Seen

    Seen: you get an event or a log Blind: nothing reports here

    1. Seen

      Your request

      Owner: Your app and your provider’s API

      What happens

      Your server asks the API to send one code to one number, naming the registered header and the registered template.

      What you can see

      The API’s reply to your request.

      The rule

      The request carries the sender ID, entity ID and template ID. Without registered values the next hop has nothing to match.

      Source: Developer page SMS sample

    2. Seen

      The template check

      Owner: The DLT platform and your access provider

      What happens

      The sender, header, wording, links and declared chain are checked against what you registered.

      What you can see

      A failed event with an error, if the message does not pass.

      The rule

      Registered headers only. The fixed part of the text must match its template. A link that is not whitelisted is not permitted.

      Source: TCCCPR regulation 3 and Schedule I; TRAI Direction, 28 Oct 2024

    3. Blind

      The operator network

      Owner: The access providers and the telemarketers in your declared chain

      What happens

      The message is carried to the recipient’s operator. It passes through at most one aggregator and one delivery telemarketer.

      What you can see

      Nothing until the delivery report arrives.

      The rule

      A message on a chain that is not declared, or does not match, is rejected.

      Source: TCCCPR regulation 22; TRAI Press Release 92/2024

    4. Blind

      The handset

      Owner: The phone and the person holding it

      What happens

      The phone has to be on, in coverage, and able to show the message.

      What you can see

      A delivered event reports a status. It does not say the person saw the code.

      The rule

      This hop is outside the checks above. Nothing you send can make the phone reachable.

      Source: No rule applies

    5. Seen

      Your verify step

      Owner: Your app

      What happens

      The person types the code and you check it.

      What you can see

      Your own logs. This is the only proof that the code reached a person.

      The rule

      Valid once, invalid after 10 minutes, at least 6 digits, wrong guesses limited.

      Source: NIST SP 800-63B-4

    You own the first and the last hop. For the three in between, what you can know is what the delivery report tells you, so design the last hop to cope when nothing arrives.

    What must be true before an OTP is sent?

    TRAI’s regulation turns into a few checks on every OTP: a registered header, a template that matches the text, no promotion mixed in, a whitelisted link if there is one, and a declared chain. An OTP needs the first three and normally no link at all.

    • Send from a registered header

      Commercial SMS may only use registered headers. Register the header, and read its format, including the -T suffix for transactional messages, on your DLT portal.

    • Register the OTP wording as a template

      The fixed part of a template is hashed so each message can be checked against it before and after delivery. Mark the code and its validity period as variables. A template has three variables by default, and belongs to one header.

    • Keep promotion out of the message

      If promotional content is mixed into a transactional message, the whole message is treated as promotional. A thank-you line with an offer is enough.

    • Leave links out

      An OTP needs no link. Traffic containing a URL, APK, OTT link or call-back number that is not whitelisted has not been permitted since 1 October 2024.

    • Know your declared chain

      A message passes through at most one aggregator and one delivery telemarketer, declared on the DLT platform. Since December 2024, SMS sent through an unregistered path is rejected, so change the declaration before you change the route.

    • Self-certify every year

      Registration details, headers and templates that are not certified each year are suspended automatically, and a suspended template stops your OTPs.

    How should the code itself be designed?

    NIST’s guidance for a code sent over SMS is short: random, at least 6 digits, used once, invalid after 10 minutes, with limits on wrong guesses. A code that expires too soon turns a slow SMS into a failure, and one that lives too long is a risk.

    • Random, 6 digits or more

      NIST asks for a random secret of at least 6 decimal digits, from an approved random generator.

    • Invalid after 10 minutes

      NIST treats the authentication as invalid unless it is completed within 10 minutes. TRAI’s thirty minutes decides the message type; it is not a validity period.

    • Valid once

      A code that has been used, or replaced by a newer one, must stop working. Resending means issuing a new code, not sending the old one again.

    • Limit wrong guesses

      NIST requires rate limiting on consecutive failed attempts, and says generating a new code must not reset the failure count. Count failures against the account or number, not the code.

    • SMS is a restricted channel

      NIST marks authentication over the phone network as restricted. Weigh risk signals such as a SIM change or a ported number, tell people about the limitation, and always offer an alternative that is not SMS.

    What do delivery reports tell you?

    Your provider reports each message’s status to a webhook you control. Ours sends message.delivered and message.failed. They tell you what happened to the message, not whether the person read it, so your verify step stays the only proof that the code arrived.

    Send SMS with DLTPython · POST /v1/sms/send
    import requests
    
    def send_sms():
        url = "https://api.notifytechai.com/v1/sms/send"
        headers = {
            "Authorization": "Bearer YOUR_API_KEY",
            "Content-Type": "application/json"
        }
        payload = {
            "to": "+919876543210",
            "message": "Your OTP is 123456",
            "sender_id": "YOUR_SENDER_ID",
            "dlt_entity_id": "1234567890123456",
            "dlt_template_id": "1234567890123456789"
        }
    
        response = requests.post(
            url, json=payload, headers=headers
        )
        return response.json()
    
    result = send_sms()
    print(result)
    Handle WebhooksPHP · webhook.php · message.delivered
    <?php
    // webhook.php - Handle delivery reports
    
    $payload = file_get_contents('php://input');
    $data = json_decode($payload, true);
    
    $signature =
      $_SERVER['HTTP_X_NOTIFYTECH_SIGNATURE'];
    $secret = 'your_webhook_secret';
    
    if (!verifySignature($payload, $signature, $secret)) {
        http_response_code(401);
        exit('Invalid signature');
    }
    
    switch ($data['event']) {
        case 'message.delivered':
            updateMessageStatus(
              $data['message_id'], 'delivered'
            );
            break;
        case 'message.failed':
            updateMessageStatus(
              $data['message_id'], 'failed'
            );
            logError($data['error']);
            break;
    }
    
    http_response_code(200);
    echo json_encode(['status' => 'processed']);

    These are the samples from the developer page. The code, the IDs and the secret are placeholders, and your template decides the text.

    Verify the signature header before you update anything. The full list of events, fields and keys is on the developer page and in the documentation. Set your own alert levels from your own baseline: a figure from someone else’s traffic is not yours.

    What should you do, and what should you avoid?

    The same advice as one ledger. Every “don’t” is a rule from TRAI, NIST or Meta that appears above, not a rule of thumb.

    1. Don’t

      Don’t: Put a link in the OTP

      Do instead

      Do: Send the code, a validity period and a warning, nothing else

      The rule

      A link that is not whitelisted is not permitted.

      Source: TRAI Direction, 28 Oct 2024

    2. Don’t

      Don’t: Add an offer or a thank-you line

      Do instead

      Do: Keep the text transactional from end to end

      The rule

      Promotional content mixed in makes the whole message promotional.

      Source: TCCCPR regulation 2

    3. Don’t

      Don’t: Change the wording without registering it

      Do instead

      Do: Register the new text as its own template first

      The rule

      The fixed part of each message is checked against its registered template.

      Source: TCCCPR Schedule I

    4. Don’t

      Don’t: Resend the same code, or accept an old one

      Do instead

      Do: Issue a new code and retire the earlier one

      The rule

      A code is valid once and for 10 minutes at most.

      Source: NIST SP 800-63B-4

    5. Don’t

      Don’t: Reset the wrong-guess count on a resend

      Do instead

      Do: Count failures per account or number

      The rule

      A new code must not reset the failure count.

      Source: NIST SP 800-63B-4

    6. Don’t

      Don’t: Treat “sent” as “received”

      Do instead

      Do: Wait for the delivery event, and let the person ask again

      The rule

      A status event is not proof that someone read the code.

      Source: Developer page webhook sample

    7. Don’t

      Don’t: Switch routes in a hurry

      Do instead

      Do: Declare the new chain first, then send

      The rule

      A chain that is not defined or does not match is rejected.

      Source: TRAI Press Release 92/2024

    8. Don’t

      Don’t: Rely on SMS alone

      Do instead

      Do: Offer a second way to sign in

      The rule

      NIST restricts the phone network as an authenticator.

      Source: NIST SP 800-63B-4

    Rules read from TRAI’s regulation, NIST and Meta on 20 October 2026. They say nothing about delivery times: no source does.

    Frequently Asked Questions

    Common questions about OTP SMS delivery in India

    1. Yes. TRAI’s regulation allows commercial SMS only through registered headers, and message wording is checked against registered content templates. An OTP is a transactional message, which needs no explicit consent from the recipient, but it still needs a registered header and template. Check your access provider’s DLT portal for the current process.

    References & Further Reading

    The regulator’s and the standard’s own documents behind this guide

    • TCCCPR 2018, consolidated

      TRAI’s Telecom Commercial Communications Customer Preference Regulations as consolidated on 21 May 2026: the definitions of an OTP and a transactional message, headers, templates and scrubbing. The gazetted text prevails.

      Read the Regulations
    • TRAI Direction, 28 October 2024

      Whitelisting of URLs, APKs, OTT links and call-back numbers, and rejection of messages whose telemarketer chain is not defined or does not match.

      Read the Direction
    • SMS traceability, Press Release 92/2024

      TRAI’s note of 19 December 2024: traffic sent through unregistered paths is rejected from 11 December 2024.

      Read the Release
    • NIST SP 800-63B-4

      Digital identity guidelines for authentication: out-of-band codes, their length and lifetime, rate limiting, and the restricted status of the phone network.

      Read the Guideline
    • WhatsApp authentication templates

      Meta’s documentation for one-time-code templates: preset body text, the optional expiry line and the code-delivery buttons.

      Read the Documentation

    Send OTPs on TRAI DLT

    NotifyTech AI’s transactional SMS runs on TRAI DLT with approved templates and priority routing, from ₹0.25/msg, with delivery events sent to your webhook.

    We use cookies to improve your experience.

    By accepting, you agree to our cookie policy and analytics tracking.