Send OTP via WhatsApp Without DLT Registration
14 July 2026
Every SMS sent to an Indian phone number for commercial purposes has to go through TRAI’s DLT (Distributed Ledger Technology) platform — you register as an entity, get your sender ID and message templates approved, and only then can carriers deliver your SMS. It typically takes days to weeks and involves paperwork most indie developers don’t want to deal with for a side project or early-stage product.
WhatsApp messages don’t go through DLT at all. They’re delivered through Meta’s WhatsApp Business Cloud API, which has its own approval process (template review by Meta) but is entirely separate from India’s telecom regulatory pipeline. If your users are willing to receive OTPs on WhatsApp — and in India, most already have WhatsApp open more often than their SMS inbox — you can skip DLT registration for that channel entirely.
What this looks like in practice
MiniMoth sends OTPs via WhatsApp first, and falls back to SMS automatically only if WhatsApp delivery fails (using MiniMoth’s own DLT-registered sender, so you never have to register one yourself either way). From your side, it’s the same two REST calls regardless of which channel actually delivers the message.
1. Send the OTP
const res = await fetch('https://api.minimoth.dev/v1/otp/send', {
method: 'POST',
headers: { 'X-Api-Key': 'mm_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({ phone: '+919876543210' }),
})
const { otp_id } = await res.json()
2. (Optional) Check delivery status
Useful if you want to show “Delivered via WhatsApp” vs “Delivered via SMS” in your UI:
const status = await fetch(`https://api.minimoth.dev/v1/otp/status/${otp_id}`, {
headers: { 'X-Api-Key': 'mm_live_...' },
}).then(r => r.json())
// { otp_id, channel: 'whatsapp' | 'sms', status: 'queued' | 'delivered' | 'failed', delivered_at }
3. Verify the code the user enters
const res = await fetch('https://api.minimoth.dev/v1/otp/verify', {
method: 'POST',
headers: { 'X-Api-Key': 'mm_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({ phone: '+919876543210', code: '123456' }),
})
const { access_token, refresh_token, expires_at } = await res.json()
That’s the whole flow — no DLT entity registration, no template submission, no waiting on carrier approval. You get an API key and start sending.
If you’re on a Node backend, @minimoth/sdk-node wraps these same calls in a typed client — and handles session refresh for you automatically. Access tokens expire after 5 minutes; instead of writing your own refresh logic and retry handling, client.session.safeValidate() detects an expired token and silently refreshes it behind the scenes, so a hassle you’d otherwise have to build yourself just doesn’t exist.
The tradeoff
Because MiniMoth uses its own DLT-registered sender for the SMS fallback channel, your users see MiniMoth’s name on the SMS (not your brand). WhatsApp messages likewise come from MiniMoth’s WhatsApp Business number. If a custom SMS sender ID showing your own brand name is a hard requirement, you’ll need to go through a full DLT registration yourself — there’s no way around that for SMS specifically, since it’s a regulatory requirement on the message content and sender, not something any provider can bypass on your behalf.
For most early-stage products, though, the sender name on an OTP message rarely matters — users care that the code arrives fast and works. If that’s you, see the quickstart to get an API key and send your first OTP.