W Agent talks to WhatsApp only through the WhatsAppProvider interface
(src/bridge/provider.ts). Swap backends with WHATSAPP_PROVIDER — agent,
outbox, ingest, MCP, and the dashboard keep the same code path.
| Value | Implementation | Status |
|---|---|---|
baileys |
src/bridge/baileys.ts |
Default. Unofficial multi-device Web session. |
meta |
src/bridge/cloudapi.ts |
Official WhatsApp Business Cloud API. |
evolution |
— | Reserved; not implemented. |
What you get
- Pair a personal (or dedicated) WhatsApp account via QR.
- Full local history sync / on-demand backfill into Postgres.
- Free-form sends that behave like the linked phone.
Trade-offs
- Uses WhatsApp’s unofficial multi-device protocol. Account ban / restriction risk is real; Meta can challenge or drop sessions without notice.
- You are responsible for send volume, quiet hours, and rate limits (
src/safety/ratelimit.ts). - No Meta Business verification — and no official support SLA.
Use a dedicated number, not your primary personal account, if you run this in production.
What you get
- Official Graph API for outbound text and template messages.
- Inbound delivery via a webhook (
GET/POST /webhookonMETA_WEBHOOK_PORT). - Same normalized
ProviderMessageevents → BullMQ ingest → agent pipeline. - No QR pairing; credentials are Meta access token + phone number id.
What you do not get
- No personal chat history access. Cloud API cannot scrape or sync an existing consumer WhatsApp history. Context is only what arrives after the webhook is live (plus anything you import yourself).
- No multi-device “link my phone” UX. This is a Business / WABA number, not your personal companion device.
- Full media / interactive / catalog parity is intentionally out of scope for the current adapter (inbound text + outbound text/templates).
Requirements / trade-offs
- Meta Business verification (and a WhatsApp Business Account) is required for production messaging limits and many template categories.
- Outside the 24-hour customer-care window you must send pre-approved templates (
CloudApiProvider.sendTemplate), not free-form text. - You must expose a public HTTPS callback URL to Meta (tunnel or reverse proxy to
META_WEBHOOK_PORT). - Pricing is Meta’s conversation-based billing, not “free like a personal phone”.
WHATSAPP_PROVIDER=meta
META_ACCESS_TOKEN=… # system user / permanent token
META_PHONE_NUMBER_ID=… # from WhatsApp → API setup
META_WEBHOOK_VERIFY_TOKEN=… # you choose; must match Meta app webhook
META_APP_SECRET=… # optional; enables X-Hub-Signature-256 checks
META_DISPLAY_PHONE_NUMBER=… # optional; builds self JID for owner notify
META_WEBHOOK_PORT=3098
META_GRAPH_API_VERSION=v21.0Meta webhook callback URL:
https://<your-public-host>/webhook
Subscribe the app to the messages field on your WABA.
With WHATSAPP_PROVIDER=meta, createProvider() returns CloudApiProvider. The
main process still calls attachIngestPipeline(provider), configureOutbound,
and the outbox sender — identical to Baileys. Inbound webhook text becomes a
ProviderMessage and enters the same ingest queue.
| Need | Prefer |
|---|---|
| Personal history + self-hosted companion agent | baileys (accept ban risk) |
| Compliant business messaging, templates, no unofficial protocol | meta |
| Already on Evolution API hosting | evolution (when implemented) |
When in doubt for anything customer-facing or high-volume: use Cloud API. Keep Baileys for personal automation on a burner number with aggressive send safety.