Skip to content

Usernames & BSUIDs

Handle WhatsApp contacts who adopted a username and hid their phone number. Receive, reply and send using business-scoped user IDs (BSUIDs).

View .md

WhatsApp users can adopt a username (like @sheena) and hide their phone number from businesses. When that happens, you no longer see their phone number anywhere: instead, every webhook and API response identifies them by a business-scoped user ID (BSUID).

Code
US.13491208655302741918

A BSUID is stable per business: the same user always has the same BSUID with you, but a different BSUID with every other business. You cannot derive a phone number from it.

Zavu handles the identity plumbing automatically. Contacts are matched and de-duplicated by BSUID, conversations stay threaded, and once Zavu learns the phone number, both identifiers point to the same contact. What you need to adapt in your integration is small, and it is all on this page.

Receiving messages from a username contact

The message.inbound webhook fires as usual, but data.from contains the BSUID instead of an E.164 phone number. data.contactId and data.whatsapp.bsuid identify the person either way:

JSON
{ "id": "evt_1705312200000_abc123", "type": "message.inbound", "timestamp": 1705312200000, "senderId": "snd_abc123", "projectId": "prj_xyz789", "data": { "messageId": "msg_xyz789", "conversationId": "js723987cyghwqxxaxcf590qd18axd95", "contactId": "jd7x2k3m4n5p6q7r8s9t0abc", "whatsapp": { "bsuid": "US.13491208655302741918", "username": "sheena" }, "from": "US.13491208655302741918", "to": "+13125559876", "channel": "whatsapp", "messageType": "text", "text": "Hi, I saw your listing", "profileName": "Sheena", "providerTimestamp": 1705312199000 } }

profileName still carries the user's display name when available, so your inbox UI has something human to show. conversationId is always the thread the message was filed in, including on the message that ties a BSUID to a phone number: that webhook names the thread that remains once the two are joined.

from can change for the same person

data.from is the phone number when WhatsApp includes it in the message, and the BSUID when it does not. WhatsApp decides that, not Zavu. As integrators have reported WhatsApp's BSUID rollout, the phone number is typically included when your business number messaged or called that person, or received a message or call from their number, in the last 30 days, or when the person is in your business portfolio's Meta contact book. Check Meta's documentation for the current rule. It can also stop being included again later.

So the same person can write to you first as US.13491208655302741918 and later as +13125551234, and back. Do not use from as the key for a person. Key on one of:

  • data.contactId: the Zavu contact. It does not change when the identifier does, except when the switch reveals two contacts for one person (see below).
  • data.whatsapp.bsuid: the BSUID, present on every WhatsApp message.inbound once Zavu knows it.

When Zavu ties a BSUID to a phone number, it sends a contact.identity_linked event, once per link:

JSON
{ "id": "evt_1705312300000_def456", "type": "contact.identity_linked", "timestamp": 1705312300000, "senderId": "snd_abc123", "projectId": "prj_xyz789", "data": { "contactId": "jd7x2k3m4n5p6q7r8s9t0abc", "bsuid": "US.13491208655302741918", "phoneNumber": "+13125551234", "reason": "provider_reported" } }
reasonMeaning
provider_reportedWhatsApp sent the phone number together with the BSUID on an inbound message.
contact_sharedThe person shared their number in reply to a request_contact_info message.
phone_changedThe person changed their WhatsApp number. previousPhoneNumber carries the old one. Sent for contacts known only by phone too, with bsuid set to null.
bsuid_changedWhatsApp reported a new BSUID for the same number. previousBsuid carries the old one.

If two contacts turned out to be the same person, they are merged: contactId is the one that remains and mergedContactId is the one that went away, so you can move what you stored under it. When the remaining contact keeps a BSUID of its own, previousBsuid carries the one you knew. Subscribe to the event on the sender's webhook. To look a contact up by BSUID, call GET /v1/contacts?bsuid=US.13491208655302741918; contacts carry the same whatsapp object.

Replying and sending to a BSUID

Pass the BSUID in to, exactly where a phone number would go. Zavu detects the format and routes it correctly on the WhatsApp API.

const message = await zavu.messages.send({ to: "US.13491208655302741918", channel: "whatsapp", text: "Thanks for reaching out! How can we help?" });

All WhatsApp message types work, including media, interactive messages and templates. The 24-hour conversation window rules are unchanged.

Two exceptions:

LimitationBehavior
Authentication templates with one-tap, zero-tap or copy-code buttonsRejected by WhatsApp (error 131062). These flows verify a phone number, so they need one. Send to the contact's phone number instead.
BroadcastsBSUID and @username recipients are rejected with a clear error. Broadcasts require phone numbers.

Recovering the phone number

If your workflow eventually needs the real phone number (calls, SMS fallback, identity verification), ask for it in the conversation. WhatsApp provides a dedicated interactive message for this: request_contact_info. It renders a fixed Share Contact Info button; when the user taps it and confirms, their phone number arrives as a regular inbound contact message.

Zavu then links the shared phone number to the BSUID contact automatically and sends contact.identity_linked with reason: "contact_shared": the contact record gains a phoneNumber, and both identifiers resolve to the same contact and conversation from that point on. This is not the only way a number gets linked: see from can change for the same person.

You can also add a request_contact_info button to a template to ask outside the 24-hour window.

Contacts in the dashboard

A contact created from a BSUID-only inbound has no phone number until Zavu learns one, either because WhatsApp includes it in a later message or because the user shares it. The dashboard contact list and inbox display the username or BSUID instead, and flag conversations where a phone number was linked from a username contact.

In the API, expect phoneNumber to be absent on these contacts, and whatsapp.bsuid to be present. Key on contactId of the inbound events to correlate messages with your own records, not on from, which can switch between the BSUID and the phone number.

Your own business username

Your WABA can reserve a business username so customers can find and message you without knowing your number. Manage it from the dashboard under Accounts → WhatsApp → your WABA: the username section shows the current username, its status (reserved, approved, deleted) and lets you set or change it. Status changes arrive automatically; there is nothing to poll.