Skip to main content

Run a WhatsApp marketing campaign end-to-end

This guide walks the full lifecycle of a business-initiated WhatsApp campaign: pick an approved template, draft the campaign with WhatsApp-specific fields, dry-run it, launch, and subscribe to the webhooks that report per-recipient outcomes. It complements the campaign end-to-end guide, which covers the channel-agnostic sequence — everything here is the WhatsApp delta: template binding, Meta’s gates, and the read/reply callbacks SMS never produces.

1. Prerequisites

  • A connected WABA with at least one approved marketing template. Business-initiated WhatsApp sends leave only as templates — there is no free-form blast equivalent. If you have not onboarded yet, start with the WABA setup guide; the 24-hour window guide explains why templates are the only permissible content outside an open customer-service window.
  • An API key with the campaigns:write scope. Reads (audience preview, dry-run, stats) accept campaigns:read; launch requires write.
  • An opted-in recipient audience. Opt-outs and suppression are enforced at send time; Meta additionally throttles marketing-template delivery for low-quality WABAs, so engagement-quality audiences matter more here than on SMS. Recipients outside the 24-hour window are reached by the template; recipients with an open window still count toward your per-recipient messaging-limit tier.

2. Pick and bind the approved template

The campaign references a template by name, and the launch pre-flights it against your locally synced template registry. A template whose Meta status is PENDING, REJECTED, PAUSED, or DISABLED fails the launch with a 422 — check the status under Channels → WhatsApp → Templates before you draft. For a single-channel WhatsApp campaign (blast or scheduled), put the template name in the top-level message_template field. For an omnichannel fallback chain, bind the template to the WhatsApp chain entry instead — an SMS or email step has no template name, so the schema rejects whatsapp_template anywhere except a channel: "whatsapp" entry: If your org’s campaign metadata declares a template_category_intent (e.g. MARKETING), launch also verifies Meta’s category on the template matches the intent — an AUTHENTICATION OTP template cannot ride a marketing blast.

3. Create the draft

The response comes back in draft status; nothing sends until step 6. Per-recipient variable values ({{1}}, {{2}}, …) resolve from contact fields the same way {{token}} personalization does on other channels — preview them with the audience sample in step 4 before launch. Fallback chains. To try WhatsApp first and fall back to SMS on terminal failure, pass a channels array whose first entry is WhatsApp carrying whatsapp_template, followed by an SMS entry:
When a chain exists, the top-level channel must equal the chain’s first entry, and whatsapp_template may only appear on the WhatsApp entry.

4. Preview the audience

Pass channel: "whatsapp" so the net projection subtracts suppression rows, WhatsApp opt-outs, and contacts with no WhatsApp-reachable number. A recipient whose only address is an email disappears from a WhatsApp preview — that cohort is your unreachable count.

5. Dry-run: the WhatsApp gates

Beyond the standard buckets (net audience, cost, quiet hours, warnings), a WhatsApp campaign is gated on Meta-specific state:
  • Template pre-flight. Launch resolves message_template against your synced template registry and requires status: "approved". A missing template name means the local registry has never seen it — sync templates from Meta, then retry.
  • Quality rating. If your WABA’s quality rating has dropped to red, the campaign auto-pauses with reason whatsapp_quality_red rather than burning quota on sends Meta will throttle anyway. Clear the quality issue in Channels → WhatsApp → Health, then resume the campaign.
  • Messaging-limit tier. The dry-run projects cost against the same resolver the send path uses, but the audience size must also fit your current per-24h unique-recipient tier (250 on a new WABA, scaling to unlimited). Check your tier under Channels → WhatsApp → Health before launching at a large list; an over-tier audience fails recipients at send time, not at launch.

6. Launch

A 422 here with a template message points back at step 2 — re-read the template status and category. A 402 or a pending-approval shape is the standard balance/approvals gate, not WhatsApp-specific.

7. Callbacks: what WhatsApp reports that SMS cannot

Subscribe to both the campaign lifecycle events and the per-message events; the webhook events catalog lists every type your endpoint can subscribe to.
  • Campaign lifecyclecampaign.started, campaign.completed, campaign.paused (including the whatsapp_quality_red auto-pause), campaign.drip_step.sent for drip shapes.
  • Per-message outcomesmessage.sent (accepted by the provider), message.delivered (device receipt), message.read (the recipient opened it — a signal SMS never produces), and message.failed carrying the Meta error code, e.g. (#132015) too many business messages when Meta throttles marketing deliveries.
  • Replies — an inbound reply inside (or opening) the 24-hour window arrives as message.received. Route it into the inbox or your own automation; the normalized inbound envelope describes the payload shape, and the webhook consumer guide covers signature verification, retries, and dead letters.
GET /api/v1/campaigns/:id/stats aggregates the same signals — sent, delivered, read (opened), replied — so the dashboard view and your webhook-driven pipeline reconcile.

8. Read rate discipline

WhatsApp surface a read receipt SMS lacks; use it. If delivered stays high but read and replied trend toward zero, Meta’s per-user marketing-frequency capping is already filtering your sends before recipients see them — shrink the audience toward engaged cohorts or move the same content into the 24-hour window as a free-form follow-up instead of another marketing template. Read the 24-hour window guide for the rules on when a reply opens that window, and the pricing guide for how marketing vs. utility template categories price each conversation.

Troubleshooting

  • Launch 422: template not found locally. The template registry has not synced the name — pull templates from Meta (Channels → WhatsApp → Templates → Sync) and retry. Re-check spelling; template names are case-sensitive.
  • Launch 422: template status is not approved. Resubmit or pick an approved template. Only APPROVED templates can send; PAUSED and DISABLED count as blocked.
  • Campaign auto-paused with whatsapp_quality_red. The WABA quality rating dropped to red. Resolve the quality issue, then POST /api/v1/campaigns/:id/resume.
  • High message.failed with Meta code (#132015). Meta is capping how many marketing-template messages one recipient receives in a window. This is recipient-side filtering, not an Orbit failure — narrow the audience or change the message category.
  • Audience preview resolves to zero. Re-run the preview with channel: "whatsapp" — the net projection names the emptying cohort (all opted out, no reachable WhatsApp number).