Tutorial

How to set up the WhatsApp Business Cloud API (2026 step-by-step)

Meta's WhatsApp Business Cloud API is the single highest-intent channel for Indian SMBs in 2026, and the docs change every few months. Here's the current setup, end-to-end, with code that runs.

May 14, 202613 min readCruxBit Team

If your customers are on WhatsApp (and in India, all of them are), the WhatsApp Business Cloud API is the channel that converts. SMS open rates are dead. Email is fine but slow. WhatsApp messages get read within minutes. The setup, though, is more bureaucratic than technical — Meta changes the dashboard flow every few months and most online guides are stale. This is the current 2026 path, including the gotchas we've hit shipping it for clients.

Two flavours of WhatsApp Business — pick the right one

The WhatsApp Business APP is the free phone app for small shops — single device, no API. The WhatsApp Business CLOUD API (what this guide covers) is Meta-hosted, supports automation, webhooks, multiple users, and is the right choice the moment you want to send transactional or marketing messages programmatically.

1. The flow you're about to wire up

Cloud API setup
Step 1               Step 2                  Step 3
─────────            ─────────────            ───────────────
Meta Business        WhatsApp Business        Verify a phone
Manager account      Account (WABA)           number (your own,
(business.            in Meta dashboard       NEW or imported
facebook.com)                                  from BSP)
   │                       │                       │
   └───────────────────────┼───────────────────────┘
                           ▼
                  Step 4: Get credentials
                  - WABA ID
                  - Phone Number ID
                  - Permanent access token
                           │
                           ▼
                  Step 5: Send first message (POST)
                           │
                           ▼
                  Step 6: Set up webhook URL
                  (incoming messages, status callbacks)
                           │
                           ▼
                  Step 7: Create + submit message templates
                  (required for business-initiated messages)

2. Create a Meta Business Manager account

  1. 1Go to business.facebook.com
  2. 2Create a new business — use your legal company name, not your personal one
  3. 3Add your business address, GST/tax ID, business website
  4. 4Add at least one admin (yourself) and verify your email

Business verification helps. A lot.

Unverified businesses are capped at 250 unique recipients per 24 hours. Verified businesses get tier upgrades automatically (1K → 10K → 100K → unlimited). Start the verification process from day one — it takes a week and unlocks every other limit.

3. Add WhatsApp to your Business

  1. 1From the Business Manager → Accounts → WhatsApp Accounts → Add
  2. 2Create a new WhatsApp Business Account (WABA) — give it a display name (the name customers see)
  3. 3Connect a phone number. Use a number that isn't currently registered on the regular WhatsApp app. If it is, you'll need to delete that WhatsApp account first (Settings → Delete my account in the consumer app)
  4. 4Choose your verification method (SMS or voice call) and complete the OTP

4. Get your credentials

From the WhatsApp → API Setup panel:

  • Temporary access token — visible immediately, expires in 24 hours. Fine for testing
  • Phone Number ID — the numeric ID of your sender
  • WhatsApp Business Account ID (WABA ID) — the numeric ID of the account
  • For production: create a System User in Business Settings → Users → System Users → Add → assign the WhatsApp app and generate a permanent token
.env.local
bash
WHATSAPP_PHONE_NUMBER_ID=123456789012345
WHATSAPP_ACCESS_TOKEN=EAAxxxxxxxx...
WHATSAPP_WEBHOOK_VERIFY_TOKEN=any-long-random-string-you-make-up
WHATSAPP_APP_SECRET=xxxxxxxxxxxxx   # for webhook signature verification

5. Send your first message (curl)

Test mode lets you send to up to 5 pre-registered numbers without templates. Add your own WhatsApp number under API Setup → Recipients.

bash
curl -X POST \
  "https://graph.facebook.com/v21.0/$WHATSAPP_PHONE_NUMBER_ID/messages" \
  -H "Authorization: Bearer $WHATSAPP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "919876543210",
    "type": "text",
    "text": { "body": "Hello from the Cloud API!" }
  }'

If you see a response with messages[0].id, the message is queued. Within a few seconds it lands on the recipient's WhatsApp. If you get an error, the most common causes are: token expired (regenerate), recipient not added to test recipients, or number format wrong (no leading +, no spaces, country code included).

6. Server-side helper (Next.js)

src/lib/whatsapp.ts
typescript
const PHONE_ID = process.env.WHATSAPP_PHONE_NUMBER_ID!;
const TOKEN = process.env.WHATSAPP_ACCESS_TOKEN!;
const API = "https://graph.facebook.com/v21.0";

async function call<T>(path: string, body: unknown): Promise<T> {
  const r = await fetch(`${API}/${path}`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  });
  if (!r.ok) {
    const err = await r.json().catch(() => ({}));
    throw new Error(`WhatsApp ${r.status}: ${JSON.stringify(err)}`);
  }
  return r.json();
}

export async function sendText(to: string, text: string) {
  return call(`${PHONE_ID}/messages`, {
    messaging_product: "whatsapp",
    to,
    type: "text",
    text: { body: text },
  });
}

export async function sendTemplate(
  to: string,
  templateName: string,
  language: string,
  variables: string[] = []
) {
  return call(`${PHONE_ID}/messages`, {
    messaging_product: "whatsapp",
    to,
    type: "template",
    template: {
      name: templateName,
      language: { code: language },
      components: variables.length
        ? [{
            type: "body",
            parameters: variables.map((v) => ({ type: "text", text: v })),
          }]
        : [],
    },
  });
}

7. The 24-hour rule (this trips up everyone)

You can only send free-form messages within 24 hours of the user sending you a message. Outside that window — including the first time you message someone — you must use an approved template.

The 24-hour conversation window
   User sends you a message
   ───────────────────────►   ┌─────────────────────────┐
                              │                         │
                              │   24-hour window OPEN   │
   You reply (any type)       │   - free text           │
   ◄───────────────────────   │   - media               │
                              │   - templates           │
                              │                         │
                              └─────────────────────────┘
                                       ▲
                                       │
                              Window closes 24h after
                              user's LAST message.
                              After: templates only.

8. Create + submit a template

Templates are created in the Meta Business Manager → WhatsApp Manager → Message Templates → Create. You write the message with {{1}}, {{2}} placeholders for variables. Meta reviews and approves within ~1 hour (sometimes minutes). Categories matter — pick correctly:

  • Marketing — promos, offers, abandoned cart. Stricter approval, costs more per send
  • Utility — order updates, OTP, account alerts, appointment reminders. Easier approval, cheaper
  • Authentication — only for one-time passwords. Cheapest tier
Example template body (utility)
text
Hi {{1}}, your order #{{2}} has been confirmed.
Expected delivery: {{3}}.
Track here: {{4}}

Pick the category honestly

If you mark a marketing template as utility to dodge fees, Meta will downgrade it on review — and your repeat offenders get the whole WABA flagged. Tag honestly from day one.

9. Webhooks — receive incoming messages

Set the webhook URL in WhatsApp → Configuration → Webhook. Use a publicly accessible HTTPS URL. The first POST will be a GET-style verification challenge — your server must echo back the hub.challenge when the token matches.

src/app/api/whatsapp/webhook/route.ts
typescript
import { NextResponse } from "next/server";
import crypto from "node:crypto";

// 1. Verification handshake (GET)
export async function GET(req: Request) {
  const url = new URL(req.url);
  const mode = url.searchParams.get("hub.mode");
  const token = url.searchParams.get("hub.verify_token");
  const challenge = url.searchParams.get("hub.challenge");
  if (
    mode === "subscribe" &&
    token === process.env.WHATSAPP_WEBHOOK_VERIFY_TOKEN
  ) {
    return new Response(challenge ?? "", { status: 200 });
  }
  return new Response("forbidden", { status: 403 });
}

// 2. Event delivery (POST)
export async function POST(req: Request) {
  const raw = await req.text();

  // Signature check — Meta signs the raw body with your app secret
  const sigHeader = req.headers.get("x-hub-signature-256") ?? "";
  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.WHATSAPP_APP_SECRET!)
    .update(raw)
    .digest("hex");

  if (
    !crypto.timingSafeEqual(
      Buffer.from(sigHeader),
      Buffer.from(expected)
    )
  ) {
    return NextResponse.json({ ok: false }, { status: 401 });
  }

  const payload = JSON.parse(raw);

  // payload.entry[*].changes[*].value.messages[*] = incoming messages
  // payload.entry[*].changes[*].value.statuses[*] = delivery / read receipts
  for (const entry of payload.entry ?? []) {
    for (const change of entry.changes ?? []) {
      const messages = change.value?.messages ?? [];
      for (const m of messages) {
        console.log("Incoming:", m.from, m.type, m.text?.body);
        // ↑ wire to your DB / chatbot / autoreply
      }
    }
  }

  return NextResponse.json({ ok: true });
}

10. Pricing in 2026 (high level)

  • Pricing is per conversation, not per message — and is tiered by category (Marketing, Utility, Authentication, Service)
  • Service conversations (user-initiated, free-form replies) — currently free for the first 1,000/month per WABA in many markets
  • Utility conversations in India — roughly ₹0.115 per conversation at the time of writing
  • Marketing conversations in India — roughly ₹0.78 per conversation
  • Numbers shift every few quarters. Always check the live developers.facebook.com/docs/whatsapp/pricing before forecasting

11. BSP or direct? When to pick which

A BSP (Business Solution Provider — like Gupshup, Wati, Interakt, Yellow.ai) wraps the same Cloud API in a UI plus extras like a CRM, inbox and chatbot builder. Trade-offs:

  • Direct Cloud API → cheapest, most control, requires you to build / buy a UI
  • BSP → faster to launch a non-technical team on, includes inbox + analytics, higher per-message cost
  • Default for SMBs with no in-house dev: a BSP. Default for product teams: Cloud API direct, build a tiny internal admin

12. Gotchas

  • Quality rating drops fast if users mark your messages as spam. Two yellow flags and your phone number gets paused. Be conservative with marketing volume
  • Templates rejected for variables in headers — keep variables in the body only, especially for utility category
  • Phone number format — international, digits only, no +, no spaces. 919876543210, not +91 98765 43210
  • Test recipients only get the first 5 numbers until you finish business verification and exit sandbox
  • Webhook timeouts — respond within 5 seconds or Meta retries. Push slow work to a queue
  • Number portability — moving a number between WABAs / BSPs is a one-week support ticket. Plan accordingly

TL;DR

  • Meta Business → WABA → verified phone number → permanent access token via a System User
  • Send free-form messages within 24h of user contact; templates outside that window
  • Categories matter — Marketing is pricier and stricter than Utility / Authentication
  • Wire webhooks with signature verification and a quick 200 (queue heavy work)
  • Start business verification immediately to unlock the higher sending tiers
  • BSP for non-dev teams; direct Cloud API if you have engineers

Building a WhatsApp-led product or rolling Cloud API out across an SMB ops team? Drop us a paragraph about the use case — we've shipped both ends of this in 2026 and will send back a candid take on the smallest setup that works for you.

#WhatsApp#Meta#API#Tutorial#SMB

Have a project?

Building something we've just written about?

Drop us a line. We respond within 24 hours with a candid, no-pressure take on whether we're the right partner.