MainSDK
Search⌘K
Integrations

MSG91

Use MSG91 for MainSDK SMS and WhatsApp notifications and WhatsApp sign-in codes in India - DLT templates, main.yaml, secrets and swapping.

1 interface1 driverWritten guide
Updated 2026-10-28

MSG91 is an India-based messaging provider for SMS and WhatsApp. In a MainSDK app it is an SMS driver and a WhatsApp channel driver for notify, and a sender for WhatsApp one-time codes in auth. Pick it when most of your users are in India and you want SMS and WhatsApp from one provider.

Interfaces it serves

Pick MSG91 in main.yaml for any of these. Your calls stay the same, and you can swap later.

Before you start

  1. Create an MSG91 account and an auth key for this app.
  2. For SMS in India, register your sender ID and message templates on the DLT platform, then add them in MSG91.
  3. For WhatsApp, connect a WhatsApp Business number through MSG91 and get your templates approved.

Store the auth key in your secrets manager.

Configure

main.in.yaml
notify:
  channels: [whatsapp, sms, push, email]
  sms: msg91
  whatsapp: msg91
  msg91:
    key: secret:MSG91_AUTH_KEY             # the auth key; this is the default name
    whatsapp:
      number: "919876500000"               # the integrated WhatsApp number
      namespace: acme_namespace            # the WhatsApp template namespace
  templates:
    order.shipped:
      sms: { template: "64f0c0ffee", vars: [orderId], dlt-template-id: "1007000000000001" }
      whatsapp: { name: order_shipped, language: en, params: [orderId] }
auth:
  whatsapp: { driver: msg91 }
  • key defaults to secret:MSG91_AUTH_KEY. A literal key fails validation with MAIN-CONFIG-0004.
  • whatsapp.number and whatsapp.namespace are needed only when notify.whatsapp is msg91.
  • MSG91 sends SMS from its own flow template, so each SMS template needs template (the MSG91 flow id) and vars, the data keys in the order the flow takes them. A template with only text is skipped on SMS with the reason failed and the code MAIN-NOTIFY-0001. Set dlt-template-id for India numbers too; without it a +91 number is skipped with MAIN-NOTIFY-0005.

What the drivers send

SMS is one POST https://control.msg91.com/api/v5/flow with an authkey header and a JSON body holding template_id, short_url: "0" and one recipient with its mobiles (digits, no plus) and the template variables. WhatsApp is one POST https://control.msg91.com/api/v5/whatsapp/whatsapp-outbound-message/bulk/ with integrated_number and a template payload: the template name, the language, the namespace, and the body variables numbered body_1, body_2 in the order of params. Both go through MainSDK's network layer, are never retried by it, do not follow redirects, and read at most 64 KiB of the answer. A 429, a 5xx or no answer is a retryable MAIN-NOTIFY-0007 and notify tries the next channel. MainSDK does not read MSG91's delivery reports.

Use it

app/orders/ship.ts
import { notify } from "mainsdk";

await notify(user, { template: "order.shipped", data: { orderId: order.id }, category: "orders" });

auth.whatsapp.send(phone) and auth.whatsapp.verify(challengeId, code) work the same with MSG91 as the sender.

Local development and testing

mainsdk dev logs one line per SMS and WhatsApp message with the number masked, when notify.sms and notify.whatsapp are local. createTestApp() from @mainsdk/testing runs notify on local channels; read them with channels(app). channels(app).sms?.failNext(1) simulates an outage, and fakeMessagingServer("msg91") records the requests the real drivers make.

What MainSDK adds on top

  • Every SMS recipient has a recorded opt-in (MAIN-NOTIFY-0003 otherwise), and India SMS uses DLT-registered templates.
  • WhatsApp only with recorded consent (MAIN-NOTIFY-0004 otherwise) and approved templates.
  • Opt-outs and quiet hours respected; a retry never sends twice.

See Notifications.

Limits and notes

  • The SMS and WhatsApp channel drivers are built (spec email-notify). The auth.whatsapp sender comes with the auth spec.
  • A MainSDK template maps to MSG91 through notify.templates.<name>.sms.template and .vars, and to a DLT template through .sms.dlt-template-id.
  • The drivers declare their own host, control.msg91.com, so network.allow does not change.

Swap to or from it

main.yaml
notify:
  sms: twilio   # was msg91

Add the new provider's block, such as notify.twilio, with it. Sending is stateless, so the swap needs no migration. Your DLT templates and WhatsApp approvals are registered per provider, so set them up with the new one first.

FAQ

Can I use MSG91 only in India? Yes. Set it in the main.in.yaml market overlay and keep another driver in main.yaml.

Does MSG91 pass the same tests as the others? Yes. The SMS cases pass for Twilio and MSG91, and the WhatsApp cases for WhatsApp Cloud API, Bird and MSG91.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet