Skip to content

    Building an SMS Notification System with an API

    Follow one SMS from the event in your app to the status in your database: the queue and retries that are yours to build, the send call and the delivery webhook that are documented.

    Stages From Event To Status
    5
    Documented Webhook Events
    2
    Code Samples
    3

    Read against the developer page and TRAI’s directions, 20 October 2026

    • NotifyTech AI Team
    • 7 min read
    • Automation

    Why an SMS needs more than one API call

    Calling the SMS API straight from the code that handles an event works for a prototype. At scale one failed call or a traffic spike means a missed OTP or order alert. A queue, a retry policy and a stored status are what make the system recoverable.

    This guide follows one message through five stages and marks which are yours and which are documented on our side. It is not legal advice: check your DLT portal for your own registrations.

    The notification path at a glance

    Send
    POST /v1/sms/send, JSON over HTTPS, API key as a Bearer token
    Reports
    message.delivered and message.failed, by signed webhook
    Queue and retries
    Yours: no idempotency key is documented
    Promotional window
    TRAI’s default is 10:00 to 21:00
    Code samples
    Node.js, Python and PHP on the developer page

    What does each kind of message need?

    Decide the kind of message before you design the queue. A one-time code, an order alert and a campaign differ in how long they can wait, and each is tied to a template you registered.

    • OTP and verification codes

      A short-lived code the user just asked for. Send it at once, and resend only when the user asks again, never from a retry that could fire twice.

    • Order updates

      Confirmed, shipped, out for delivery. Queue each one once the order is stored, and keep one record per event so a retry cannot send it twice.

    • Payment updates

      Received, refunded, invoiced. One message per payment event, keyed on the payment’s own ID.

    • Reminders

      Appointments, delivery slots, due dates. These can wait in the queue, so check that the booking and the time are still current just before you send.

    • Promotional campaigns

      A campaign needs a promotional template. TRAI’s default window for promotional SMS is 10:00 to 21:00, so a campaign queued at night waits for the morning.

    • Links in the text

      A URL, APK, OTT link or call-back number that is not whitelisted has not been permitted in SMS since 1 October 2024. Whitelist a link on your DLT portal before it goes into a template.

    Why does the send sit behind a queue?

    So a traffic spike or a failed call never blocks your app or loses a message. The queue, the retry policy and the failed-jobs set are yours to build; the API call inside the worker is a single request.

    • Store the event, then queue it

      Write the event and its status to your database first. If a worker dies, the row shows what still has to be sent.

    • One event, one SMS

      Key each job on your own event ID, so a duplicate event cannot queue a second message.

    • Retry transient errors, then stop

      Back off between attempts and stop at a limit you choose. The example uses three attempts with exponential backoff; those are the example’s numbers, not a recommendation from us.

    • Check before you resend

      No idempotency key is documented for the send call, so a retry after a timeout can send twice. Look up your record of the send before you try again.

    • Know your plan’s rate limit

      Keep the worker’s concurrency under it. The Rate Limiting & Throttling guide in our documentation library has the limits; we send it on request.

    • Keep a failed-jobs set

      Messages that run out of retries go somewhere a person can see, with the error attached.

    How do delivery reports come back?

    By a webhook you control, not by polling. Ours sends message.delivered and message.failed, signed with X-NotifyTech-Signature. SMS has no read receipt, so Delivered is the last status you will see.

    • Events by webhook, not by polling

      The developer page documents two events, message.delivered and message.failed. It documents no endpoint for polling a message’s status, so store what the webhook tells you. Give us your webhook URL when you get your keys.

    • Verify the signature, then reply 200

      Each webhook carries an X-NotifyTech-Signature header. The sample checks it against your webhook secret, answers 401 if it does not match, and replies 200 once the event is handled.

    • Keep the status per message

      Update one row per message from each event, and keep the error from message.failed beside it.

    • No report means unknown

      If nothing arrives for a message, call it unknown, not failed and not delivered. A Delivered status is also not proof that a person read the message.

    Is a second provider a code swap?

    No. A fallback provider is a registration question before it is a code question. Your header, template and telemarketer chain have to match what you declared, so a second provider has to be registered before it can carry traffic.

    • A header that is registered

      Commercial SMS may only use registered headers. A new provider means a header registered through that provider before it can send as you.

    • A template that matches

      Each message is checked against a registered template, and a template belongs to one header. Moving traffic means registering the template again, not copying the text.

    • A declared telemarketer chain

      Since December 2024, a message whose chain is not defined, or does not match the declared one, is rejected. Changing provider is also a change to your registration.

    In what order do you build it?

    Schema first, queue second, API call third. Each step gives the next one something to record against, so the order matters more than the speed.

    1. Step 1: Design your event schema

      List every user action that should send a message, the template each one maps to and the payload the worker needs.

    2. Step 2: Set up the queue

      Pick the queue, then set its concurrency, retry policy and failed-jobs set before you write any SMS code.

    3. Step 3: Call the send endpoint

      Add the API client, map each event to your registered DLT template and call the endpoint from the worker.

    4. Step 4: Implement retries

      Add backoff and failed-job handling, and test the failure cases against a mock endpoint of your own.

    5. Step 5: Wire up the delivery webhook

      Give us your webhook URL when you get your keys, verify the signature on each request and store the status.

    6. Step 6: Add monitoring

      Track failures and sent messages with no report in your own monitoring, and log each failure with its error.

    What does the whole path look like?

    One message, from the event in your app to the status in your table. Three stages are yours and two are documented on our side. Pick a stage to see its code or its rules.

    You build and run this Documented on the developer page

    Yours

    Something happens in your app

    An order is placed, a payment clears, a user asks for a code. Nothing here touches our API: your code decides that an event needs a message and which registered template it uses.

    • Store the event before you queue it
    • Key it on your own ID so one event sends one SMS
    • Map it to a template you have registered

    What to record per event

    Event ID
    Your own key. A duplicate event finds the existing row and stops.
    Recipient and template
    The number and the registered template this event uses.
    Status
    Starts as queued.
    Time
    When it was queued, so a reminder can check it is still current.

    An example record, not a NotifyTech AI schema.

    Frequently Asked Questions

    Common questions about building an SMS notification system

    1. A queue keeps a traffic spike or a failed call off the code that handles the event, and gives retries somewhere to live. Without one, an error at the wrong moment can mean a missed OTP or order alert. The queue and its retry policy are yours to build; the API call inside the worker is one request.

    References & Further Reading

    TRAI’s own documents behind the registration rules in this guide

    • TCCCPR 2018, consolidated

      TRAI’s Telecom Commercial Communications Customer Preference Regulations as consolidated on 21 May 2026: the rules for senders, headers, templates, consent 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 undefined or does not match.

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

      TRAI’s December 2024 note on the chain declaration and the rejection of messages sent through unregistered paths.

      Read the Release

    Request your API keys

    Tell us what you are building and we will set up your API keys. Real people on support, Mon–Sat, 9–7 IST.

    We use cookies to improve your experience.

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