Send SMS, OTPs, email and WhatsApp messages and read delivery reports through MSG91.
MSG91 ships in the w6w first-party pack. It declares 16 actions, 3 health checks, and the host runs its code in a sandbox that never sees the credential.
io.w6w.msg91MSG91 is an Indian cloud-communications platform (CPaaS) for transactional and marketing messaging. This app drives its v5 API from a workflow.
SMS goes out through DLT-approved templates (flows) to one or many numbers with per-recipient variables. One-time passwords can be sent, verified and resent by text or voice, with the verify step returning a plain true/false instead of an error when the code is wrong or expired. Email sends from a template through a verified domain with cc, bcc, reply-to, variables and attachments, and any address can be checked for deliverability, disposable domains and role addresses.
On WhatsApp it sends approved templates to one or many recipients, sends in-session text replies, and lists the integrated numbers, a number’s templates and its prepaid balance. Delivery logs (OTP, email, WhatsApp; three-day windows) and SMS analytics (31 days) close the loop.
Voice, RCS, Segmento contacts, campaigns, the Hello inbox, sub-accounts, template creation, the OTP widget and OneAPI flows are not part of this app.
Three routes to the same 16 actions. The Workflow tab is generated from MSG91's own manifest and carries its real ids, so it is copy-pasteable; the Code and CLI examples are the same call for any action on any app, so every app-specific value in them is a blank you fill in.
email-send Send an email from an MSG91 email template through a verified sending domain, with template variables.
email-templates-list List the email templates in your MSG91 account, optionally filtered by name or status.
email-validate Check whether an email address is deliverable, disposable, a free-mail or a role address.
otp-resend Resend the same OTP to the number it was first sent to, by text or voice call (MSG91 allows 2 retries).
otp-send Generate and send a one-time password by SMS from an MSG91 OTP template. MSG91 stores it for Verify OTP.
otp-verify Check an OTP the user typed against the one MSG91 sent. Returns verified true/false; a rejected key or bad input fails the step.
sms-analytics Delivery analytics for SMS sent in a date range (at most 31 days, starting no earlier than 2024-01-01).
sms-send Send an SMS from a DLT-approved MSG91 template (flow) to one or many numbers, with per-recipient variables.
whatsapp-balance-get Read the prepaid balance and plan status for an integrated WhatsApp number.
whatsapp-message-send Send a free-form text message to a user who has already messaged you (an open WhatsApp session). Use Send WhatsApp Template to start a conversation.
whatsapp-numbers-list List the WhatsApp numbers integrated with your MSG91 account.
whatsapp-template-send Send an approved WhatsApp template message from an integrated number to one or many recipients.
whatsapp-templates-list List the WhatsApp templates linked to an integrated number (MSG91 returns at most 500).
A workflow step names the app and the action, and the editor fills in the
connection when you pick one. This is the Step shape from the
workflow spec, carrying MSG91's real ids.
{
"manifestVersion": "2",
"name": "msg91-example",
"steps": [
{
"id": "email-logs",
"uses": {
"app": "io.w6w.msg91",
"action": "email-logs",
"connection": "conn_YOUR_CONNECTION_ID"
},
"with": {
"startDate": "<startDate>",
"endDate": "<endDate>"
}
}
]
}email-logs email-send email-templates-list email-validate otp-logs +11 more actions available
Every app-specific value here is a blank you have to fill in. An
app action is reached through the connection that authenticates it, so the
address is a connection id, not the app id — and connections belong to your account,
so a public page cannot know yours. Create one for MSG91, then fill in
the three blanks: conn_YOUR_CONNECTION_ID, the action key, and the
parameters that action declares. The call itself is real — the shape is transcribed
from the studio's own snippet builder, which prints the same kind of blanks — but
nothing in it is specific to MSG91. The Workflow tab is where this app's
real ids are.
npm install @w6w/sdkyarn add @w6w/sdkpnpm add @w6w/sdkdeno add npm:@w6w/sdkimport { W6wClient, isActionRun } from "@w6w/sdk";
// Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
const client = new W6wClient();
const envelope = await client.run({
urn: "conn_YOUR_CONNECTION_ID",
action: "email-logs",
payload: {
startDate: "<value>",
endDate: "<value>",
// requestId: "<value>",
// fields: "<value>",
// limit: "<value>",
},
});
if (isActionRun(envelope)) console.log(envelope.value); npm install -g @w6w/cli w6w run conn_YOUR_CONNECTION_ID --action email-logs --payload '{"startDate":"<value>","endDate":"<value>"}' Give an AI agent MSG91 — without giving it MSG91's credentials. One MCP endpoint exposes every app, function and workflow the caller is entitled to, as tools it can discover and run. Access is granted per team while we onboard.
One tool call{
"name": "w6w_invoke",
"arguments": {
"ref": "app:io.w6w.msg91#email-logs",
"input": {
"startDate": "<startDate>",
"endDate": "<endDate>"
}
}
}
Every tool names its target with a single ref. The
app: form above doesn't name a connection at all — the
host resolves which of the caller's MSG91 connections to sign
with, and refuses rather than guesses when the answer is ambiguous.
The token is attached host-side, at the moment of the call. It is never a tool argument, never in the model's context, and never in a transcript — so a prompt injection has nothing to exfiltrate.
Tools are derived per end user from what that person has actually connected and is entitled to — not one shared bot identity carrying the union of everyone's access.
Multi-step work runs on the workflow engine and returns a run handle the agent can poll — retries, branching and state survive the conversation that started them.
MSG91's declared health checks are on the surface too, so an agent can tell "the vendor is down" from "your credential expired" before it burns a retry on either.
The MCP surface is part of the hosted platform. MSG91 itself is MIT, and the runtime that executes it is source-available (FSL).
MSG91 declares its own checks, so its health is a property of the app rather than something the host guesses at.
Unsigned GET https://control.msg91.com/api/v5/whatsapp/whatsapp-activation/. A schema-correct JSON refusal proves the API is answering; an HTML body is not the API.