WhatsApp Identity Model¶
Meta is rolling out WhatsApp Usernames and Business Scoped User IDs (BSUID) for Cloud API. Customers may message a business without exposing their phone number.
ConnectGain stores multiple WhatsApp identifiers per contact and matches inbound messages using this priority:
whatsapp_bsuidwhatsapp_jid(including@lidprivacy JIDs on Baileys/WhatsApp Lite)whatsapp_phone/contacts.phones[]whatsapp_username(match only — outbound send requires phone, BSUID, or JID)
Schema¶
Dedicated columns on contacts:
| Column | Purpose |
|---|---|
whatsapp_phone |
Normalized E.164 when known |
whatsapp_jid |
Full JID (@s.whatsapp.net, @lid, etc.) |
whatsapp_username |
@handle without leading @ |
whatsapp_bsuid |
Meta Business Scoped User ID |
Indexed via contact_whatsapp_identity_index (service-role lookups at webhook scale).
Inbound flow¶
All three WhatsApp webhooks parse identifiers and call findOrCreateContactByWhatsAppIdentity:
whatsapp-cloud-webhook— Meta Cloud API / Pabblyappgain-whatsapp-webhook— primary WhatsApp Lite (Appgain/Baileys)whatsapp-lite-webhook— legacy flat Appgain payload
Raw identity snapshots are stored on messages.metadata.whatsapp_identity for monitoring.
Contacts without a resolvable phone receive the whatsapp_phone_pending tag.
Outbound flow¶
Send functions resolve recipients via resolveWhatsAppRecipient:
- Phone → Meta
to/ AppgainmobileNum - BSUID → Meta
to(Cloud API) - JID → Appgain
mobileNum(Lite; logged asphone_missing_jid_send)
Phone request flow¶
When a contact has BSUID/JID/username but no phone:
- Tag:
whatsapp_phone_pending - Agent or bot sends a message asking the customer to share their phone number
- On next inbound with phone, identities merge onto the existing contact (no duplicate)
Monitoring (Baileys / Lite)¶
Lite webhooks emit structured logs with event whatsapp_identity_anomaly when:
usernameis present@lidJID is seen- Phone is missing but another identifier exists
Key files¶
| File | Role |
|---|---|
| the platform | Parse, match, merge, send resolution |
| the platform | Schema + RPC |
| the platform | Frontend send guards |
Testing¶
Test matrix:
- Inbound with phone only (regression)
- Inbound with username only
- Inbound with BSUID only
- Existing phone contact later messages via username → merge
- Outbound by BSUID/JID when phone null
- Phone-request CTA → phone arrives → identity merge