ADR 002: WhatsApp Integration โ Twilio Meta Cloud API + Number Pool
Date: 2026-04-30 Status: Accepted (Twilio + pool model). The sender-whitelist routing decision below was superseded on 2026-05-05 โ see Update section.
Decisionโ
Use Twilio as the Business Solution Provider (BSP) for Meta's WhatsApp Cloud API. Pre-provision a standing pool of ~20 WhatsApp numbers (one per Specialist persona) rather than provisioning numbers per client Org.
Architectureโ
- One number per Specialist from a pre-provisioned pool
- Twilio subaccounts: staging and production each have separate credentials
- Sender whitelist per Org controls who can initiate conversations (superseded โ see Update below)
- Inbound routing: message arrives on Specialist number โ lookup sender โ find Org โ route to Expert Queue
Rationaleโ
- Official Meta Cloud API โ no ToS violation, no ban risk
- Numbers scale with Specialists (~20), not Orgs (could be hundreds)
- Free trial Orgs cost nothing extra
- Twilio subaccount isolation keeps prod credentials away from developers
Consequencesโ
- Requires one-time Meta Business Account verification
- Each Specialist number costs ~$1/month
- Outbound messages cost ~$0.005 (Twilio) + Meta per-message rate
Update โ 2026-05-05: Pairing codes supersede the sender whitelistโ
What changed: The "Sender whitelist per Org controls who can initiate conversations" mechanism is replaced by a self-service pairing-code flow. The original whitelist is retained only as a legacy routing fallback for orgs onboarded before this change; new orgs do not configure it.
New mechanism:
- Each user generates a one-time
HW-XXXXcode from the portal (Settings โ WhatsApp), 15-minute TTL, stored inwhatsapp_pairing_codes. - Texting that code from WhatsApp links the sender's phone to
(userId, orgId)via a newwhatsapp_linked_numberstable. - The inbound handler routes by checking, in order: (1) pairing-code message, (2)
whatsapp_linked_numbers, (3)whatsapp_sender_whitelist(fallback), (4) unknown-sender auto-reply. - Re-pairing the same phone to a different org is rejected without burning the code; the existing link must be removed from the dashboard first.
Why the change:
- The whitelist required AMs to know each client's phone number in advance โ fragile and high-friction.
- Number changes silently broke routing.
- No self-service path for clients; every change required HP intervention.
- Pairing captures the phone at link time (self-reported by the device), supports re-linking on number changes, and is fully self-service.
Tracking: GitHub issue #191 (closed on landing).
Related docs: docs/features/channels.md (WhatsApp section), docs/ops/TWILIO-SETUP-CHECKLIST.md (Sections 8 & 9).