• Home
  • Blog
  • WhatsApp OTP Verification: How It Works (with Code)
Guides
11 min read May 18, 2026

WhatsApp OTP Verification: How It Works (with Code)

A practical, balanced guide to sending one-time passwords over WhatsApp: authentication templates, the Cloud API send payload, one-tap autofill, cost vs SMS, rate limits, and compliance — with real code.

Key takeaways
  • OTPs over WhatsApp must use a pre-approved AUTHENTICATION-category message template sent through Meta's WhatsApp Cloud API — you cannot send a free-form code, and the legacy On-Premises API shut down on October 23, 2025.
  • The send payload has a load-bearing quirk: the code must appear twice — once in the body parameter and once in the button (sub_type 'url', index '0') parameter. Omitting either fails.
  • One-tap autofill and zero-tap are Android-only and require an app handshake (package name + signing-key hash). iOS and other clients fall back to a copy-code button.
  • Authentication messages are priced aggressively (often around $0.006 vs roughly $0.04 for SMS in many markets) since Meta moved to per-message pricing on July 1, 2025; deliverability and speed numbers come mostly from Meta/vendors, not independent audits.
  • There is no reliable official pre-send 'is this number on WhatsApp' check — the contacts endpoint now returns a valid status regardless — so design an SMS fallback for non-WhatsApp users.

Why send OTPs over WhatsApp at all?

One-time passwords are the workhorse of phone-based authentication: a short code, valid for a few minutes, that proves a user controls a number during login, sign-up, password reset, or step-up verification. For years SMS was the only realistic channel. Today WhatsApp is a serious alternative, and Meta is actively pushing it as an authentication channel — both with pricing and with native client features.

The appeal is concrete. WhatsApp delivers OTPs inside an encrypted, app-native conversation rather than the open SMS network, which sidesteps a lot of SMS-specific fraud (SIM-swap interception is harder, and there is no SMS-pumping toll-fraud surface where attackers farm premium routes). On Android, WhatsApp can also autofill the code with a single tap, removing the copy-paste friction that hurts conversion. And in many markets it is now dramatically cheaper per message than SMS.

This guide walks through how WhatsApp OTP actually works end to end — the official channel, the authentication template anatomy, the exact send payload (including a common bug), the one-tap handshake, real cost and deliverability tradeoffs, rate limits, and the compliance lines you should not cross. It is deliberately balanced: WhatsApp is excellent for OTP, but it is not a drop-in replacement for SMS in every case.

The only sanctioned channel: WhatsApp Cloud API

To send production OTPs you use the WhatsApp Business Platform's Cloud API, hosted by Meta on the Graph API. Messages go to a single endpoint: POST https://graph.facebook.com/<version>/<PHONE_NUMBER_ID>/messages, where the version is a recent Graph release (v22.0–v23.0 are current in 2025–2026). This is now the only first-party path: Meta shut down the legacy On-Premises API on October 23, 2025, so any tutorial pointing you at a self-hosted on-prem container is out of date.

Crucially, you cannot send an OTP as a normal text message. Authentication codes must be delivered using a pre-approved message template whose category is literally AUTHENTICATION. You create templates by POSTing to /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates and waiting for Meta to approve them. This is what keeps the channel clean — the template format is constrained, and free-form code delivery is simply not allowed.

Anatomy of an authentication template

Authentication templates are intentionally rigid — Meta controls the wording so codes are recognizable and hard to abuse. You do not write the body copy; you pick from fixed strings and toggle options. The pieces are:

  • Body (fixed, non-customizable): the text is always "<VERIFICATION_CODE> is your verification code." Only the code variable changes.
  • Footer security disclaimer (optional, fixed string): "For your security, do not share this code."
  • Expiration warning (optional, fixed): "This code expires in <NUM_MINUTES> minutes."
  • Button: choose one of three delivery styles — one-tap autofill, copy code, or zero-tap (no visible button).
  • Code value: up to 15 characters; alphanumeric codes are allowed, not just digits.

Because the copy is fixed, getting a template approved is usually fast and low-friction — there is little for a reviewer to reject. The interesting decision is which button type to use, and that choice has real platform-dependent behavior, covered next.

The send flow — and the bug everyone hits

Once your authentication template is approved, sending an OTP is one HTTP call. Here is the verified shape for a copy-code template. Note the detail that trips up almost everyone: the code appears twice — once in the body component and once in the button component.

BASH
curl -X POST 'https://graph.facebook.com/v23.0/<PHONE_NUMBER_ID>/messages' \
  -H 'Authorization: Bearer <ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{
    "messaging_product": "whatsapp",
    "to": "<RECIPIENT_PHONE_E164>",
    "type": "template",
    "template": {
      "name": "<AUTH_TEMPLATE_NAME>",
      "language": { "code": "en_US" },
      "components": [
        { "type": "body", "parameters": [ { "type": "text", "text": "123456" } ] },
        { "type": "button", "sub_type": "url", "index": "0",
          "parameters": [ { "type": "text", "text": "123456" } ] }
      ]
    }
  }'

Generate and store the code on your own server (hash it, attach an expiry, rate-limit attempts), pass the plaintext into both parameters at send time, and verify the user's input against your stored value. WhatsApp delivers the code; your backend owns the lifecycle — generation, expiry, attempt limits, and validation.

One-tap autofill, copy-code, and zero-tap

The button type controls the user experience, and the single most important accuracy point is this: one-tap autofill and zero-tap are Android-only. On iOS and any non-Android client, WhatsApp automatically falls back to the copy-code button. So design for copy-code as the baseline and treat autofill as a progressive enhancement for Android users.

Button typeUser actionPlatform support
Copy codeTaps a button to copy the code, then pastes it into your appAll platforms (universal fallback)
One-tap autofillTaps once; WhatsApp passes the code straight into your appAndroid only (needs app handshake)
Zero-tapNo interaction; code is delivered to the app automaticallyAndroid only (needs app handshake)

One-tap and zero-tap require a handshake so WhatsApp can hand the code to the right app securely. Your Android app implements a public class WhatsApp can invoke via an intent, and at template creation you register a supported_apps entry containing the package_name and the signature_hash (the hash of your app's signing key). The handshake must be initiated within 10 minutes before the message is sent, and the package name plus signature hash in the message must match the installed app. If they do not match, WhatsApp silently replaces the autofill button with a copy-code button — which is why a misconfigured handshake looks like "autofill just isn't working."

Cost and deliverability vs SMS

Meta moved from conversation-based to per-message pricing on July 1, 2025, and prices authentication messages aggressively because it wants WhatsApp to be the default auth channel. In many markets an authentication message lands around $0.006 versus roughly $0.04 for an equivalent SMS — often a multiple cheaper. Authentication-international rates apply to certain markets, and as part of the same pricing update Meta reduced authentication rates in several high-volume markets. Rates change and vary by destination, so always price your specific markets against Meta's current rate card before committing.

FactorWhatsApp OTPSMS OTP
Typical cost (many markets)~$0.006 / message~$0.04 / message
Reported delivery success~99.5% (Meta/vendor)~94–98% (vendor)
Reported delivery time~2–4s (Meta/vendor)~5–7s (vendor)
ReachOnly users on WhatsAppAny working mobile number
AutofillAndroid (iOS native from 2026)iOS/Android OS-level
Fraud surfaceEncrypted, no SMS-pumpingSIM-swap, SMS-pumping toll fraud

Table caption: the cost, success-rate, and speed figures above are Meta/vendor-reported, not independent audits — treat them as directional, not guaranteed.

Treat the success-rate and speed figures with care: they come largely from Meta and channel vendors, not independent audits. Meta has cited internal results from January–February 2025 — for example a reported +20% Instagram account-recovery success, +11% on Facebook, and +9% on new Instagram account creation after adding WhatsApp OTP — but those are first-party numbers describing Meta's own products. The honest framing is: WhatsApp OTP is typically cheaper and at least competitive on delivery, with the big caveat that it only reaches people who actually use WhatsApp.

Can you check if a number is on WhatsApp first?

The obvious optimization is to check whether a number is even on WhatsApp before you spend a message and risk a silent failure. Unfortunately there is no fully reliable official way to do this. The old contacts endpoint that historically answered this question is now effectively deprecated and unreliable: it returns a valid status and a WhatsApp ID regardless of whether the number is actually on WhatsApp. Do not build a pre-send existence gate on top of it — it will tell you everyone is reachable.

The practical pattern is send-and-handle-failure: attempt the WhatsApp OTP, watch the delivery status webhook, and fall back to SMS for numbers that don't deliver. That fallback is non-negotiable if your audience isn't 100% on WhatsApp — otherwise non-WhatsApp users simply can't log in. Avoid unofficial scrapers for this check; they re-introduce the exact ToS and ban problems you avoided by using the Cloud API.

Where a separate, read-only validity signal genuinely helps is upstream of OTP entirely — for example deduplicating or scoring a signup list, or routing channels before a campaign. For those non-authentication use cases, a dedicated number-validation API (such as our WhatsApp Profile API) can tell you whether a number is on WhatsApp and surface the public profile picture, display name, about text, and business flag, without you sending anything. Just don't treat any external check as a guarantee for the OTP send itself — keep the SMS fallback.

Rate limits, scaling, and compliance

Sending volume is governed by messaging tiers: 250 → 1K → 10K → 100K → unlimited unique recipients per 24 hours. You move up by sending to enough unique users while keeping a green quality rating. Note the post-October-2025 change: a low quality rating now only caps your ability to move up a tier — limits are no longer automatically downgraded on a quality dip. Severe quality or policy problems are a separate, harsher consequence: they can get the phone number restricted or disabled entirely, which is not the same as a tier 'throttle-down.' Since October 2025 these limits are tracked per Business Portfolio rather than per phone number, and business verification is required to send OTPs at scale — an unverified Tier 0 account cannot run a real OTP workload.

TierUnique recipients / 24h
Tier 0 (unverified)Limited / not for scale
Tier 1250
Tier 21,000
Tier 310,000
Tier 4100,000
Tier 5Unlimited

On compliance, the Cloud API is the low-risk path when you do three things: collect genuine opt-in consent before messaging, send only approved AUTHENTICATION templates, and keep your quality rating green. Stay inside those lines and ban risk is minimal. Step outside them — buying lists, sending unsolicited messages, or reaching for an unofficial library to dodge template approval — and you re-enter ToS-violation territory with real account-loss risk. For OTP specifically, the official API is the only defensible production choice.

Putting it together

A robust WhatsApp OTP setup looks like this: an approved AUTHENTICATION template, a backend that owns code generation and expiry, a send call that puts the code in both the body and the button parameters, copy-code as the universal experience with one-tap as an Android enhancement, and an SMS fallback for non-WhatsApp users and delivery failures. Add business verification before you scale, and watch your quality rating like a metric that matters — because it gates how high you can scale, and lets policy problems escalate to a restricted number if you ignore it.

Done this way, WhatsApp OTP is cheaper than SMS in most markets, fast, encrypted, and pleasant to use on Android — with iOS catching up natively in 2026. The two things to internalize are the double-parameter send quirk and the lack of a reliable pre-send existence check. Handle those and the rest is straightforward.

Frequently asked questions

Validate numbers before you message

Before a campaign or signup flow, our hosted WhatsApp Profile API tells you whether a number is on WhatsApp and returns the public profile picture, display name, about text, and business flag — read-only, no QR scan, no ban risk. A clean upstream signal so your OTP and outreach hit real, reachable users.

Explore the WhatsApp Profile API

Sources & further reading

Related

More from the blog

Written by
Eduardo Airaudo

Developer and founder of the WhatsApp Profile API. Building WhatsApp tooling and APIs since 2022.

What Our Users Say

Real reviews from our satisfied customers

4.5/5 (170 reviews)