This page covers BSUID-related webhook payload changes. For the high-level transition guide, start with Meta BSUID, Usernames & Contact Book Transition Guide.
Scope
The changes affect more than the basic incoming messages webhook. BSUID, parent BSUID, username, and optional phone-number fields can appear across:
- incoming messages,
- sent, delivered, read, and failed status webhooks,
- system messages,
user_preferences,user_id_update,- contacts messages from
REQUEST_CONTACT_INFO, - Coexistence
history,smb_message_echoes, andsmb_app_state_sync, - Groups API webhooks,
- Calling API webhooks.
Quick Reference
Outbound Status Webhooks
For sent, delivered, and read statuses:
| Identifier | Sent to phone number | Sent to BSUID |
|---|---|---|
wa_id | Always included | Included only if phone number is available under Meta's phone-number rules. |
user_id | Always included | Always included. |
recipient_user_id | Always included | Always included. |
parent_user_id | Included if parent BSUIDs are enabled. | Included if parent BSUIDs are enabled. |
recipient_parent_user_id | Included if parent BSUIDs are enabled. | Included if parent BSUIDs are enabled. |
username | Included in delivered/read if the user has a username. | Included in delivered/read if the user has a username. |
For failed status webhooks, the contacts array is omitted. recipient_user_id is also omitted if the failed message was sent to a phone number.
Incoming Messages
| Identifier | User has username | User does not have username |
|---|---|---|
wa_id | Included only if phone number is available under Meta's phone-number rules. | Always included. |
user_id | Always included. | Always included. |
parent_user_id | Included if parent BSUIDs are enabled. | Included if parent BSUIDs are enabled. |
username | Included. | Omitted. |
Incoming Messages
Incoming message payloads add BSUID fields while making phone-number fields conditional.
| Field | Behavior |
|---|---|
contacts[].profile.username | Present if the user has adopted a username. |
contacts[].wa_id | Can be omitted if the user has a username and phone-number conditions are not met. |
contacts[].user_id | The user's BSUID. |
contacts[].parent_user_id | Parent BSUID when enabled. |
messages[].from | Can be omitted under the same conditions as wa_id. |
messages[].from_user_id | The user's BSUID. |
messages[].from_parent_user_id | Parent BSUID when enabled. |
messages[].group_id | Present for incoming group messages. |
Minimal username-era incoming message shape:
{
"contacts": [
{
"profile": {
"name": "Sheena Nelson",
"username": "realsheenanelson"
},
"user_id": "US.13491208655302741918",
"parent_user_id": "US.ENT.11815799212886844830"
}
],
"messages": [
{
"from_user_id": "US.13491208655302741918",
"from_parent_user_id": "US.ENT.11815799212886844830",
"id": "wamid...",
"timestamp": "1749416383",
"type": "text",
"text": {
"body": "Does it come in another color?"
}
}
]
}
Status Messages
Status webhooks add a contacts array for sent, delivered, and read statuses. Failed statuses omit contacts.
| Field | Behavior |
|---|---|
contacts[].profile.name | User display name. |
contacts[].profile.username | Present for delivered/read if the user has a username. Omitted for sent. |
contacts[].wa_id | Included only when Meta can include the phone number. |
contacts[].user_id | The user's BSUID. |
contacts[].parent_user_id | Parent BSUID when enabled. |
statuses[].recipient_id | Phone number or group ID when available; can be omitted for BSUID sends. |
statuses[].recipient_user_id | The user's BSUID. Omitted on failed statuses if the original send used a phone number. |
statuses[].recipient_parent_user_id | Parent BSUID when enabled. |
Your delivery-status pipeline should not require contacts[], contacts[].wa_id, or statuses[].recipient_id.
System and User ID Updates
When a WhatsApp user changes their phone number, Meta can send a system message with:
system.typeset touser_changed_user_id,system.user_idset to the new BSUID,system.parent_user_idset to the new parent BSUID if enabled,system.wa_idset to the new phone number only if it can be included.
Meta is also adding a user_id_update webhook field. It contains a user_id object with previous and current BSUID values, and a parent_user_id object when parent BSUIDs are enabled.
Store both previous and current IDs so you can merge CRM identities instead of creating a new customer thread.
Contact and Preference Webhooks
REQUEST_CONTACT_INFO and direct contact-sharing messages trigger a contacts message. The message adds:
messages[].from_user_id,messages[].contacts[].originwithcontact_requestorother,messages[].contacts[].vcardwhen the user shared a contact directly (origin: "other"),- phone number details in
messages[].contacts[].phones[].
user_preferences webhooks add user_id and parent_user_id both in contacts[] and user_preferences[]. Their wa_id fields can be omitted when phone-number inclusion rules are not met.
Coexistence Fields
Coexistence direct-routed fields also gain BSUID data:
| Field | BSUID changes |
|---|---|
history | Threads can include context.user_id, context.parent_user_id, and context.username. Messages can include from_user_id and from_parent_user_id. |
smb_message_echoes | Adds contacts[], to_user_id, and to_parent_user_id; to can be omitted. |
smb_app_state_sync | Contact objects can include user_id, parent_user_id, and username; phone_number can be omitted. |
Consumer revoke and edit messages | Add from_user_id, from_parent_user_id, and optional username in contacts. |
In Dualhook setups, history, smb_message_echoes, and smb_app_state_sync go directly to your endpoint via Webhook Override.
Groups and Calling Webhooks
Group and calling surfaces also change:
- group delivered/read status webhooks add contact
user_id, parent BSUID, and username fields; recipient_participant_idcan be omitted, whilerecipient_participant_user_idis added;group_participants_updatepayloads adduser_id,parent_user_id, andusernamefor participant events;- calling
callswebhooks addfrom_user_id,to_user_id,recipient_user_id, and parent equivalents depending on direction and event type; - SIP signaling can carry BSUIDs in SIP URIs and
x-wa-meta-user-id,x-wa-meta-parent-user-id, andx-wa-meta-usernameheaders.
If you use groups or calling, update those parsers too. This transition is not limited to message text webhooks.
Webhook Testing
Meta's App Dashboard webhook tester supports username adoption scenarios for message webhooks:
- user has not adopted a username: BSUID and phone-number fields are present, username omitted;
- user has adopted a username and phone number is unavailable: username and BSUID fields are present, phone-number fields are omitted;
- user has adopted a username and phone number is available: username, BSUID, and phone-number fields are present;
- parent BSUID present: parent BSUID fields appear alongside regular BSUIDs.
Use these tests against your real webhook handler, not only a schema validator.
Dualhook Handling
Dualhook does not ingest message-path BSUID payloads. With Webhook Override, Meta sends messages, history, smb_message_echoes, and smb_app_state_sync directly to your endpoint.
Dualhook cannot replay missed BSUID webhook payloads or backfill BSUID mappings into your CRM. Treat BSUID support as an application-side migration in your webhook receiver and downstream systems.