Summary
Meta is launching WhatsApp Usernames — users will be able to set an @username and hide their phone number from businesses. To support this, Meta is adding a Business-Scoped User ID (BSUID) to all webhook payloads via a new user_id field.
Starting June 2026, the wa_id / from fields that currently always contain a phone number may contain a BSUID instead (format: CC.alphanumeric, e.g. BR.1A2B3C4D5E6F7G8H9I0J...). This will break Chatwoot's contact resolution for username-adopting users.
Timeline
| Date |
What happens |
| Early April 2026 |
Contact Book feature — Meta auto-stores phone+BSUID pairs from prior interactions |
| May 2026 |
BSUIDs start appearing in all webhook payloads (testing phase) |
| June 2026 |
Usernames launch in test countries — wa_id may be BSUID, not phone |
| August 2026+ |
Global rollout |
What breaks in Chatwoot
Chatwoot currently uses the phone number (wa_id) as the primary identifier for WhatsApp contacts:
Whatsapp::IncomingMessageBaseService resolves contacts via wa_id assuming it's always a phone number
ContactInbox uses source_id (phone number in E.164) with a unique index on (inbox_id, source_id)
find_or_create_contact maps phone number → Contact record
When a username-adopting user messages a business and their phone number is not in the Contact Book:
wa_id / from will be a BSUID, not a phone number
- Chatwoot will create a duplicate contact (new
source_id with the BSUID) instead of matching the existing contact
- Sending replies may fail if the code assumes
wa_id is always E.164
Webhook payload changes
New field user_id — always present in all message webhooks (regardless of username adoption):
{
"contacts": [{"profile": {"name": "Jessica"}, "wa_id": "BR.1A2B3C4D5E6F7G8H9I0J..."}],
"messages": [{
"from": "BR.1A2B3C4D5E6F7G8H9I0J...",
"user_id": "BR.1A2B3C4D5E6F7G8H9I0J...",
"id": "wamid.xxx",
"type": "text",
"text": {"body": "Hello"}
}]
}
For users without usernames, wa_id remains a phone number, but user_id (BSUID) is still present.
Suggested approach
- Store
user_id (BSUID) — add a bsuid / whatsapp_user_id column to ContactInbox or Contact
- Dual-key contact resolution — match by BSUID first, fall back to phone number, write BSUID back when matched by phone
- Detect BSUID vs phone — BSUIDs have the format
CC.alphanum (2-letter country code + dot + up to 128 chars), phone numbers are E.164
- Handle sending to BSUIDs — when no phone number is known, use the BSUID as the recipient identifier in the Cloud API
References
Environment
- Self-hosted Chatwoot CE (latest)
- WhatsApp Cloud API with coexistence mode
- Affects all WhatsApp Cloud API integrations
I'm happy to contribute a PR if the team can provide guidance on the preferred approach for contact resolution changes.
Summary
Meta is launching WhatsApp Usernames — users will be able to set an
@usernameand hide their phone number from businesses. To support this, Meta is adding a Business-Scoped User ID (BSUID) to all webhook payloads via a newuser_idfield.Starting June 2026, the
wa_id/fromfields that currently always contain a phone number may contain a BSUID instead (format:CC.alphanumeric, e.g.BR.1A2B3C4D5E6F7G8H9I0J...). This will break Chatwoot's contact resolution for username-adopting users.Timeline
wa_idmay be BSUID, not phoneWhat breaks in Chatwoot
Chatwoot currently uses the phone number (
wa_id) as the primary identifier for WhatsApp contacts:Whatsapp::IncomingMessageBaseServiceresolves contacts viawa_idassuming it's always a phone numberContactInboxusessource_id(phone number in E.164) with a unique index on(inbox_id, source_id)find_or_create_contactmaps phone number → Contact recordWhen a username-adopting user messages a business and their phone number is not in the Contact Book:
wa_id/fromwill be a BSUID, not a phone numbersource_idwith the BSUID) instead of matching the existing contactwa_idis always E.164Webhook payload changes
New field
user_id— always present in all message webhooks (regardless of username adoption):{ "contacts": [{"profile": {"name": "Jessica"}, "wa_id": "BR.1A2B3C4D5E6F7G8H9I0J..."}], "messages": [{ "from": "BR.1A2B3C4D5E6F7G8H9I0J...", "user_id": "BR.1A2B3C4D5E6F7G8H9I0J...", "id": "wamid.xxx", "type": "text", "text": {"body": "Hello"} }] }For users without usernames,
wa_idremains a phone number, butuser_id(BSUID) is still present.Suggested approach
user_id(BSUID) — add absuid/whatsapp_user_idcolumn toContactInboxorContactCC.alphanum(2-letter country code + dot + up to 128 chars), phone numbers are E.164References
Environment
I'm happy to contribute a PR if the team can provide guidance on the preferred approach for contact resolution changes.