Context
WhatsApp is launching usernames — an optional privacy feature that lets users hide their phone number when messaging businesses. To support this, Meta is introducing a Business-Scoped User ID (BSUID) as a new way to identify users.
Timeline
| Date |
Event |
| Early April 2026 |
Meta launches "contact book" feature (auto-stores phone/BSUID pairs) |
| May 2026 |
Testing phase — user_id field starts appearing in webhooks |
| June 2026 |
Username rollout begins in test countries |
| August 2026 |
Global rollout |
BSUID Format
- Pattern:
CC.alphanumeric (2-letter country code + dot + up to 128 alphanumeric chars)
- Example:
BR.1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T
- Twilio wraps it as
whatsapp:CC.BSUID (max 140 chars with prefix)
Webhook Payload Changes (Cloud API)
A new user_id field will appear in all message webhooks, even for users without usernames:
{
"contacts": [{"profile": {"name": "Jessica"}, "wa_id": "BR.1A2B3C..."}],
"messages": [{
"from": "BR.1A2B3C...",
"user_id": "BR.1A2B3C...",
"type": "text",
"text": {"body": "Hello"}
}]
}
- User without username:
wa_id/from = phone number, user_id = BSUID
- User with username:
wa_id/from = BSUID (no phone), user_id = BSUID
- Phone numbers auto-returned for a rolling 30 days after any phone-based interaction
- Auth templates (one-tap, zero-tap, copy-code) still require phone numbers
What needs to change in maia-messaging
1. _normalize_phone() in providers/meta.py
Currently assumes to is always a phone number (strips whatsapp: and +). Must detect BSUID vs phone and pass BSUIDs through without stripping the +.
2. Message type documentation
WhatsAppText.to, WhatsAppMedia.to, MetaWhatsAppTemplate.to now accept both phone numbers and BSUIDs.
3. Gateway phone fallback (gateway.py)
Phone fallback/denormalization logic must skip BSUID recipients — no Brazil phone normalization applies.
4. Types (optional)
Consider whether a user_id / bsuid field should be added to message or result types for the consuming app to pass through.
5. Twilio provider
Twilio adds a new ExternalUserId field mapping to BSUID. The to/from fields may contain a BSUID when no phone is available. Same detection logic needed.
References
Context
WhatsApp is launching usernames — an optional privacy feature that lets users hide their phone number when messaging businesses. To support this, Meta is introducing a Business-Scoped User ID (BSUID) as a new way to identify users.
Timeline
user_idfield starts appearing in webhooksBSUID Format
CC.alphanumeric(2-letter country code + dot + up to 128 alphanumeric chars)BR.1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0Twhatsapp:CC.BSUID(max 140 chars with prefix)Webhook Payload Changes (Cloud API)
A new
user_idfield will appear in all message webhooks, even for users without usernames:{ "contacts": [{"profile": {"name": "Jessica"}, "wa_id": "BR.1A2B3C..."}], "messages": [{ "from": "BR.1A2B3C...", "user_id": "BR.1A2B3C...", "type": "text", "text": {"body": "Hello"} }] }wa_id/from= phone number,user_id= BSUIDwa_id/from= BSUID (no phone),user_id= BSUIDWhat needs to change in
maia-messaging1.
_normalize_phone()inproviders/meta.pyCurrently assumes
tois always a phone number (stripswhatsapp:and+). Must detect BSUID vs phone and pass BSUIDs through without stripping the+.2. Message type documentation
WhatsAppText.to,WhatsAppMedia.to,MetaWhatsAppTemplate.tonow accept both phone numbers and BSUIDs.3. Gateway phone fallback (
gateway.py)Phone fallback/denormalization logic must skip BSUID recipients — no Brazil phone normalization applies.
4. Types (optional)
Consider whether a
user_id/bsuidfield should be added to message or result types for the consuming app to pass through.5. Twilio provider
Twilio adds a new
ExternalUserIdfield mapping to BSUID. Theto/fromfields may contain a BSUID when no phone is available. Same detection logic needed.References