BF WABA Expert (WhatsApp Cloud API)
Direct, production-grade integration and diagnostics for Meta's WhatsApp Cloud API (Graph API v26.0). Zero intermediary BSPs (no Twilio, Zenvia, Wassenger) and zero MCP dependencies.
When to Use
Activate this skill whenever:
- Implementing, reviewing, or fixing WhatsApp Cloud API direct integrations (
graph.facebook.com).
- Sending messages: text, media (image, audio, video, document), interactive (buttons, list, catalog, CTA), location, contacts, reactions, or templates.
- Configuring webhooks: GET verification handshake, POST payload parsing, HMAC-SHA256 signature verification, and delivery/read/failed status processing.
- Investigating silent delivery failures: webhook returns 200 OK or panel shows "connected successfully" but customer messages never arrive.
- Managing WhatsApp Business Accounts (WABA): System User Tokens, phone number registration, 2-step verification, display names, and Coexistence (App + Cloud API on same number).
- Working with message templates (marketing, utility, authentication), variable mapping, and the 24-hour service window.
- Scaffolding or debugging backend implementations in Node.js (TypeScript) or Python (FastAPI/httpx).
Quick Reference (Graph API v26.0)
| Parameter |
Value |
| Base URL |
https://graph.facebook.com/v26.0 |
| Send Messages |
POST /{phone-number-id}/messages |
| Upload Media |
POST /{phone-number-id}/media |
| Query Media URL |
GET /{media-id} |
| WABA Subscribed Apps |
POST /{waba-id}/subscribed_apps (Critical!) |
| Webhook Field Subs |
POST /{app-id}/subscriptions |
| Auth Header |
Authorization: Bearer {system-user-or-access-token} |
| Signature Header |
X-Hub-Signature-256: sha256={hmac_hash} |
| Phone Format |
Strictly E.164: +{country_code}{number} without spaces, dashes, or leading zeros |
| Rate Limits |
Cloud API: 80 msgs/sec default tier (scales up to 500+ msgs/sec based on quality) |
| Pricing Model |
Per-message pricing (effective since July 2025; service window rules updated 2026) |
Core Operational Law: The 3 Silent Failure Modes
In Meta's Cloud API, the default failure mode is silence. No error is returned, the developer dashboard shows green checks, test webhooks succeed, yet customer messages never arrive. Always check these three invisible steps:
- WABA Not Subscribed to the App:
- Meta requires explicitly binding the WABA to your App ID. Without this, webhook pings from the dashboard work, but real customer messages are dropped silently.
- Fix:
POST https://graph.facebook.com/v26.0/{WABA_ID}/subscribed_apps
- Webhook Field Subscriptions Missing:
- The app must subscribe specifically to the
messages and smb_message_echoes fields under whatsapp_business_account. Updating your webhook URL in Meta Dashboard frequently unchecks these fields silently!
- Fix:
POST https://graph.facebook.com/v26.0/{APP_ID}/subscriptions?object=whatsapp_business_account&fields=messages,smb_message_echoes (requires App Access Token {app_id}|{app_secret}).
- Token Expiration & Missing Asset Assignment:
- Temporary dashboard tokens expire after 24h. Production requires a Permanent System User Token.
- Simply having the permissions
whatsapp_business_messaging and whatsapp_business_management is not enough: the WABA asset must be explicitly assigned to the System User in Business Manager (business.facebook.com → Accounts → WhatsApp Accounts → Assign People / System Users).
Automated Healing with diagnose.py
Run the bundled diagnostic script to identify and automatically repair these issues:
# Inspection & report only:
python scripts/diagnose.py
# Automatically subscribe WABA and webhook fields:
python scripts/diagnose.py --fix
Architecture & Workflows
1. Inbound Webhook Pipeline
A production webhook server must execute three steps in strict order:
Meta GET Handshake ──► Verify hub.verify_token ──► Return hub.challenge as text/plain (200 OK)
Meta POST Event ──► Compute HMAC-SHA256 (raw body) ──► Constant-time compare X-Hub-Signature-256
──► Return 200 OK immediately (<3s) ──► Dispatch payload to async worker/queue
Security Invariants:
- Reflected XSS Prevention: Always respond to
hub.challenge with Content-Type: text/plain and validate challenge character set (^[A-Za-z0-9_\-]+$).
- Timing Attacks: Validate signatures using constant-time comparison (
crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python).
- Fast Ack (<3s): Meta retries exponentially if your webhook takes longer than 3 seconds. Return 200 OK before heavy business logic or AI processing.
- Idempotency: WhatsApp webhooks may retry delivery. Deduplicate incoming events by
entry[].changes[].value.messages[].id.
2. Outbound Messaging Pipeline
All messages use POST /{phone-number-id}/messages.
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "5511999999999",
"type": "text",
"text": { "body": "Olá! Como posso ajudar?", "preview_url": false }
}
- Session Window (24h): Free-form messages (text, media, interactive, audio, location) can only be sent within 24 hours of the user's last inbound message.
- Outside 24h Window: You must use an approved Meta Message Template (
type: "template"). Sending free-form text outside the window returns error 131047 (Re-engagement message).
- Mark as Read: Always acknowledge customer messages to display blue double ticks:
POST /{phone-number-id}/messages with {"messaging_product": "whatsapp", "status": "read", "message_id": "<ID>"}.
Message Types Quick Guide
| Type |
Payload Key |
Key Constraints |
| Text |
"text": {"body": "..."} |
Max 4,096 chars. Markdown formatting: *bold*, _italic_, ~strike~, code. |
| Image |
"image": {"id": "..."} or {"link": "..."} |
JPG, PNG. Max 5 MB. Caption max 1,024 chars. |
| Audio / Voice |
"audio": {"id": "..."} |
AAC, MP4, AMR, MP3, OGG (codecs=opus for PTT). Max 16 MB. |
| Document |
"document": {"id": "...", "filename": "..."} |
PDF, DOCX, XLSX, etc. Max 100 MB. |
| Interactive Buttons |
"interactive": {"type": "button", ...} |
Max 3 quick-reply buttons. Button title max 20 chars. |
| Interactive List |
"interactive": {"type": "list", ...} |
Max 10 rows total across all sections. Button title max 20 chars. |
| Reaction |
"reaction": {"message_id": "...", "emoji": "👍"} |
Single UTF-8 emoji or "" to remove reaction. |
| Location |
"location": {"latitude": -23.55, "longitude": -46.63} |
Lat/Long float, optional name and address. |
| Template |
"template": {"name": "...", "language": {"code": "pt_BR"}} |
Pre-approved in WhatsApp Manager. Components: header, body, button. |
| Flows |
"interactive": {"type": "nfm_reply", ...} |
Form-based native workflows (Flow JSON 7.3). |
Full payload schemas and examples available in references/messaging-types.md.
Troubleshooting & Error Taxonomy
| Error Code |
Meaning |
Root Cause & Resolution |
| 190 |
Invalid OAuth Access Token |
Token expired or revoked. Generate a permanent System User Token. |
| 100 |
Invalid Parameter |
Invalid phone number format (must be E.164) or malformed JSON payload. |
| 131030 |
Recipient phone number not in allowed list |
Test numbers in Development mode can only message numbers added to the recipient whitelist in Developer Dashboard. |
| 131047 |
Re-engagement message |
24-hour customer service window is closed. Outbound message must be an approved Template. |
| 131051 |
Unsupported message type |
Payload structure doesn't match the declared type attribute. |
| 131052 |
Media download error |
Media URL unreachable, returned non-200, or took too long to respond. |
| 131053 |
Media upload error |
File format not supported or exceeded file size limit for the media type. |
| 130429 |
Rate limit hit |
Sending too fast for current messaging tier (Tier 1: 1k, Tier 2: 10k, Tier 3: 100k, Tier 4: Unlimited per 24h). Implement exponential backoff. |
Full error catalog and field diagnoses in references/troubleshooting-and-diagnostics.md.
Bundled Tools & Scripts
The skill provides production utilities in the scripts/ directory:
scripts/diagnose.py: Full diagnostic and auto-repair utility.
- Inspects access token validity, expiration, and scopes.
- Verifies phone number display status and verified name.
- Queries and binds WABA app subscription (
--fix).
- Checks and registers webhook field subscriptions (
--fix).
- Simulates external Meta GET handshake test.
scripts/send_test_message.py: Validates outbound message delivery with E.164 sanitization.
scripts/validate_config.py: Audits local .env configuration.
scripts/setup_project.py: Scaffolds a full Node.js or Python WhatsApp Cloud API microservice with secure webhooks and typed clients.
Project Boilerplates
Pre-configured boilerplates ready to drop into projects:
- Node.js (TypeScript):
assets/boilerplate/nodejs/
- Express server with raw-body HMAC validation middleware.
- Complete TypeScript types for all incoming/outgoing payloads.
- Typed
WhatsAppClient with automatic retries and exponential backoff.
- Python (FastAPI):
assets/boilerplate/python/
- FastAPI server with async
httpx client.
- HMAC-SHA256 request validator decorator.
- Template manager and media upload/download utilities.
Detailed References
For deep-dive documentation, consult the files in references/:
- references/api-reference-v26.md — Endpoints, auth tokens, headers, rate limits, and pricing.
- references/messaging-types.md — Exact JSON payload specifications for every message type.
- references/webhooks-and-security.md — HMAC validation, signature headers, payload models, and deduplication.
- references/templates-and-lifecycle.md — Template creation, approval guidelines, and parameter mapping.
- references/troubleshooting-and-diagnostics.md — Silent failures, error codes, and Coexistence runbook.
- references/coexistence-and-compliance.md — Coexistence setup, opt-in rules, and quality rating management.
1---2name: bf-waba-expert3description: Full Meta WhatsApp Cloud API (WABA) senior integration expert — direct Graph API v26.0 (no BSP, no MCP). Covers sending all message types (text, media, interactive buttons/lists, catalog, flows, templates, reactions, location, contacts), webhook setup with HMAC-SHA256 verification and anti-XSS challenge handling, System User Tokens, 24h service windows, per-message pricing model, Flow JSON 7.3, Coexistence, automated diagnostics with --fix, and resolving the 3 silent failure modes (WABA unsubscribed, missing webhook fields, token asset assignment, opaque error codes). Includes production Node.js/TypeScript and Python boilerplates. Triggers on any mention of WhatsApp Cloud API, WABA, Meta Graph API WhatsApp, WhatsApp webhooks, templates, messaging, or troubleshooting silent WhatsApp delivery failures.4license: MIT5---67# BF WABA Expert (WhatsApp Cloud API)89Direct, production-grade integration and diagnostics for **Meta's WhatsApp Cloud API (Graph API v26.0)**. Zero intermediary BSPs (no Twilio, Zenvia, Wassenger) and zero MCP dependencies.1011---1213## When to Use1415Activate this skill whenever:16- Implementing, reviewing, or fixing WhatsApp Cloud API direct integrations (`graph.facebook.com`).17- Sending messages: text, media (image, audio, video, document), interactive (buttons, list, catalog, CTA), location, contacts, reactions, or templates.18- Configuring webhooks: GET verification handshake, POST payload parsing, HMAC-SHA256 signature verification, and delivery/read/failed status processing.19- Investigating **silent delivery failures**: webhook returns 200 OK or panel shows "connected successfully" but customer messages never arrive.20- Managing WhatsApp Business Accounts (WABA): System User Tokens, phone number registration, 2-step verification, display names, and Coexistence (App + Cloud API on same number).21- Working with message templates (marketing, utility, authentication), variable mapping, and the 24-hour service window.22- Scaffolding or debugging backend implementations in Node.js (TypeScript) or Python (FastAPI/httpx).2324---2526## Quick Reference (Graph API v26.0)2728| Parameter | Value |29|---|---|30| **Base URL** | `https://graph.facebook.com/v26.0` |31| **Send Messages** | `POST /{phone-number-id}/messages` |32| **Upload Media** | `POST /{phone-number-id}/media` |33| **Query Media URL** | `GET /{media-id}` |34| **WABA Subscribed Apps** | `POST /{waba-id}/subscribed_apps` (Critical!) |35| **Webhook Field Subs** | `POST /{app-id}/subscriptions` |36| **Auth Header** | `Authorization: Bearer {system-user-or-access-token}` |37| **Signature Header** | `X-Hub-Signature-256: sha256={hmac_hash}` |38| **Phone Format** | Strictly E.164: `+{country_code}{number}` without spaces, dashes, or leading zeros |39| **Rate Limits** | Cloud API: 80 msgs/sec default tier (scales up to 500+ msgs/sec based on quality) |40| **Pricing Model** | Per-message pricing (effective since July 2025; service window rules updated 2026) |4142---4344## Core Operational Law: The 3 Silent Failure Modes4546In Meta's Cloud API, **the default failure mode is silence**. No error is returned, the developer dashboard shows green checks, test webhooks succeed, yet customer messages never arrive. Always check these three invisible steps:47481. **WABA Not Subscribed to the App:**49 - Meta requires explicitly binding the WABA to your App ID. Without this, webhook pings from the dashboard work, but real customer messages are dropped silently.50 - Fix: `POST https://graph.facebook.com/v26.0/{WABA_ID}/subscribed_apps`512. **Webhook Field Subscriptions Missing:**52 - The app must subscribe specifically to the `messages` and `smb_message_echoes` fields under `whatsapp_business_account`. Updating your webhook URL in Meta Dashboard frequently unchecks these fields silently!53 - Fix: `POST https://graph.facebook.com/v26.0/{APP_ID}/subscriptions?object=whatsapp_business_account&fields=messages,smb_message_echoes` (requires App Access Token `{app_id}|{app_secret}`).543. **Token Expiration & Missing Asset Assignment:**55 - Temporary dashboard tokens expire after 24h. Production requires a **Permanent System User Token**.56 - Simply having the permissions `whatsapp_business_messaging` and `whatsapp_business_management` is **not enough**: the WABA asset must be explicitly **assigned** to the System User in Business Manager (`business.facebook.com` → Accounts → WhatsApp Accounts → Assign People / System Users).5758### Automated Healing with `diagnose.py`5960Run the bundled diagnostic script to identify and automatically repair these issues:6162```bash63# Inspection & report only:64python scripts/diagnose.py6566# Automatically subscribe WABA and webhook fields:67python scripts/diagnose.py --fix68```6970---7172## Architecture & Workflows7374### 1. Inbound Webhook Pipeline7576A production webhook server must execute three steps in strict order:7778```79Meta GET Handshake ──► Verify hub.verify_token ──► Return hub.challenge as text/plain (200 OK)80Meta POST Event ──► Compute HMAC-SHA256 (raw body) ──► Constant-time compare X-Hub-Signature-25681 ──► Return 200 OK immediately (<3s) ──► Dispatch payload to async worker/queue82```8384*Security Invariants:*85- **Reflected XSS Prevention:** Always respond to `hub.challenge` with `Content-Type: text/plain` and validate challenge character set (`^[A-Za-z0-9_\-]+$`).86- **Timing Attacks:** Validate signatures using constant-time comparison (`crypto.timingSafeEqual` in Node.js, `hmac.compare_digest` in Python).87- **Fast Ack (<3s):** Meta retries exponentially if your webhook takes longer than 3 seconds. Return 200 OK before heavy business logic or AI processing.88- **Idempotency:** WhatsApp webhooks may retry delivery. Deduplicate incoming events by `entry[].changes[].value.messages[].id`.8990### 2. Outbound Messaging Pipeline9192All messages use `POST /{phone-number-id}/messages`.9394```json95{96 "messaging_product": "whatsapp",97 "recipient_type": "individual",98 "to": "5511999999999",99 "type": "text",100 "text": { "body": "Olá! Como posso ajudar?", "preview_url": false }101}102```103104- **Session Window (24h):** Free-form messages (text, media, interactive, audio, location) can **only** be sent within 24 hours of the user's last inbound message.105- **Outside 24h Window:** You **must** use an approved Meta Message Template (`type: "template"`). Sending free-form text outside the window returns error `131047` (`Re-engagement message`).106- **Mark as Read:** Always acknowledge customer messages to display blue double ticks:107 `POST /{phone-number-id}/messages` with `{"messaging_product": "whatsapp", "status": "read", "message_id": "<ID>"}`.108109---110111## Message Types Quick Guide112113| Type | Payload Key | Key Constraints |114|---|---|---|115| **Text** | `"text": {"body": "..."}` | Max 4,096 chars. Markdown formatting: `*bold*`, `_italic_`, `~strike~`, ````code````. |116| **Image** | `"image": {"id": "..."}` or `{"link": "..."}` | JPG, PNG. Max 5 MB. Caption max 1,024 chars. |117| **Audio / Voice** | `"audio": {"id": "..."}` | AAC, MP4, AMR, MP3, OGG (codecs=opus for PTT). Max 16 MB. |118| **Document** | `"document": {"id": "...", "filename": "..."}` | PDF, DOCX, XLSX, etc. Max 100 MB. |119| **Interactive Buttons** | `"interactive": {"type": "button", ...}` | Max 3 quick-reply buttons. Button title max 20 chars. |120| **Interactive List** | `"interactive": {"type": "list", ...}` | Max 10 rows total across all sections. Button title max 20 chars. |121| **Reaction** | `"reaction": {"message_id": "...", "emoji": "👍"}` | Single UTF-8 emoji or `""` to remove reaction. |122| **Location** | `"location": {"latitude": -23.55, "longitude": -46.63}` | Lat/Long float, optional `name` and `address`. |123| **Template** | `"template": {"name": "...", "language": {"code": "pt_BR"}}` | Pre-approved in WhatsApp Manager. Components: `header`, `body`, `button`. |124| **Flows** | `"interactive": {"type": "nfm_reply", ...}` | Form-based native workflows (Flow JSON 7.3). |125126*Full payload schemas and examples available in [references/messaging-types.md](references/messaging-types.md).*127128---129130## Troubleshooting & Error Taxonomy131132| Error Code | Meaning | Root Cause & Resolution |133|---|---|---|134| **190** | Invalid OAuth Access Token | Token expired or revoked. Generate a permanent System User Token. |135| **100** | Invalid Parameter | Invalid phone number format (must be E.164) or malformed JSON payload. |136| **131030** | Recipient phone number not in allowed list | Test numbers in Development mode can only message numbers added to the recipient whitelist in Developer Dashboard. |137| **131047** | Re-engagement message | 24-hour customer service window is closed. Outbound message must be an approved **Template**. |138| **131051** | Unsupported message type | Payload structure doesn't match the declared `type` attribute. |139| **131052** | Media download error | Media URL unreachable, returned non-200, or took too long to respond. |140| **131053** | Media upload error | File format not supported or exceeded file size limit for the media type. |141| **130429** | Rate limit hit | Sending too fast for current messaging tier (Tier 1: 1k, Tier 2: 10k, Tier 3: 100k, Tier 4: Unlimited per 24h). Implement exponential backoff. |142143*Full error catalog and field diagnoses in [references/troubleshooting-and-diagnostics.md](references/troubleshooting-and-diagnostics.md).*144145---146147## Bundled Tools & Scripts148149The skill provides production utilities in the `scripts/` directory:1501511. **`scripts/diagnose.py`**: Full diagnostic and auto-repair utility.152 - Inspects access token validity, expiration, and scopes.153 - Verifies phone number display status and verified name.154 - Queries and binds WABA app subscription (`--fix`).155 - Checks and registers webhook field subscriptions (`--fix`).156 - Simulates external Meta GET handshake test.1572. **`scripts/send_test_message.py`**: Validates outbound message delivery with E.164 sanitization.1583. **`scripts/validate_config.py`**: Audits local `.env` configuration.1594. **`scripts/setup_project.py`**: Scaffolds a full Node.js or Python WhatsApp Cloud API microservice with secure webhooks and typed clients.160161---162163## Project Boilerplates164165Pre-configured boilerplates ready to drop into projects:166- **Node.js (TypeScript):** `assets/boilerplate/nodejs/`167 - Express server with raw-body HMAC validation middleware.168 - Complete TypeScript types for all incoming/outgoing payloads.169 - Typed `WhatsAppClient` with automatic retries and exponential backoff.170- **Python (FastAPI):** `assets/boilerplate/python/`171 - FastAPI server with async `httpx` client.172 - HMAC-SHA256 request validator decorator.173 - Template manager and media upload/download utilities.174175---176177## Detailed References178179For deep-dive documentation, consult the files in `references/`:180- [references/api-reference-v26.md](references/api-reference-v26.md) — Endpoints, auth tokens, headers, rate limits, and pricing.181- [references/messaging-types.md](references/messaging-types.md) — Exact JSON payload specifications for every message type.182- [references/webhooks-and-security.md](references/webhooks-and-security.md) — HMAC validation, signature headers, payload models, and deduplication.183- [references/templates-and-lifecycle.md](references/templates-and-lifecycle.md) — Template creation, approval guidelines, and parameter mapping.184- [references/troubleshooting-and-diagnostics.md](references/troubleshooting-and-diagnostics.md) — Silent failures, error codes, and Coexistence runbook.185- [references/coexistence-and-compliance.md](references/coexistence-and-compliance.md) — Coexistence setup, opt-in rules, and quality rating management.