Skip to main content

Migrating to WhatsApp Business-Scoped User IDs

WhatsApp is rolling out usernames, so people can be reached on WhatsApp without handing out their phone number. For businesses, WhatsApp replaces the phone number with a Business-scoped user ID (BSUID) -- an identifier that is issued to your business for that person.

For most integrations this is a small change with one sharp edge: a WhatsApp contact may no longer have a phone number at all. Anything in your system that assumes "one WhatsApp contact = one phone number" needs attention.

Short version

SendSeven captures Business-scoped user IDs automatically, keeps them attached to the right contact, and picks the correct wire format when sending. What you have to change is your own identifier assumptions: read WhatsApp identifiers from contact_methods[] instead of the contact's phone, and never "clean up" a BSUID value.

What WhatsApp Is Changing

BeforeNow
Sender identity on inboundPhone number (whatsapp_id)Phone number and a Business-scoped user ID
Username adoptersDid not existPhone number is withheld entirely -- only the BSUID arrives
SendingAddress the phone numberAddress the phone number or the BSUID
ScopeA phone number is a phone number everywhereA BSUID only works from the WhatsApp Business portfolio that issued it

Two consequences matter:

  1. Every inbound WhatsApp message now carries a Business-scoped user ID for the sender, whether or not that person adopted a username. SendSeven stores it while the phone number is still visible, which is what keeps the contact reachable if they adopt a username later.
  2. Once someone adopts a username, their phone number stops arriving. From that point the BSUID is the only way to reach them on WhatsApp -- and there is no way to reach them on SMS, RCS, or a phone call at all until they choose to share their number.

What a BSUID Looks Like

US.13491208655302741918
  • A two-letter country code, a period, then up to 128 letters and digits.
  • Some businesses also see parent IDs, which carry an extra segment: US.ENT.11815799212886844830.
  • It is opaque. There is no meaning to extract, and the country code is not a routing prefix.
The periods are part of the identifier

Stripping, replacing, or "normalizing" the periods produces a value WhatsApp rejects. Store and transmit BSUIDs byte for byte as you received them. If your pipeline runs phone-number cleanup over WhatsApp identifiers, exclude BSUIDs from it.

How SendSeven Represents It

A Business-scoped user ID is a contact method with method_type: "whatsapp_bsuid".

PropertyValue
method_typewhatsapp_bsuid
valueThe BSUID exactly as WhatsApp issued it, periods included
channel_idRequired. The WhatsApp channel the ID belongs to
display_nameThe contact's public WhatsApp username, when known -- a label only
{
"id": "cm_wab_001",
"contact_id": "contact_d4e5f6a7",
"method_type": "whatsapp_bsuid",
"value": "US.13491208655302741918",
"channel_id": "ch_123",
"display_name": "@alexrivera",
"is_primary": true,
"created_at": "2026-08-04T09:12:00Z"
}

It is a separate type, not a wider whatsapp_id

whatsapp_id is normalized as a phone-style identifier: a leading +, spaces, dashes, parentheses and periods are stripped. Running that over US.13491208655302741918 would silently store US13491208655302741918 -- a well-formed-looking value that WhatsApp refuses at send time. So BSUIDs get their own slot, and posting one into whatsapp_id returns 422 with a pointer to whatsapp_bsuid.

It is channel-scoped

A BSUID is issued by a WhatsApp Business portfolio and only works when messaging from a phone number in that portfolio. channel_id is therefore required, exactly as it is for messenger_id and instagram_id. A contact who writes to two of your WhatsApp numbers can hold two whatsapp_bsuid methods, one per channel.

It may be the contact's only identifier

For a username adopter there is no phone and no whatsapp_id method -- the BSUID is created as the contact's primary method and stands alone. That contact is complete and reachable; it is not a broken record.

The username is not addressable

A WhatsApp username (@alexrivera) cannot be used as a recipient by any API. SendSeven keeps it on the method's display_name so your agents and your UI can show it, and nothing more.

What SendSeven Handles Automatically

BehaviourWhat happens
Inbound captureEvery inbound WhatsApp message stores the sender's BSUID as a whatsapp_bsuid method on the contact, scoped to the receiving channel
Phone-number-less sendersWhen WhatsApp discloses no phone number, the BSUID becomes the contact's primary method and no phone/whatsapp_id method is invented
Contact matchingAn inbound BSUID resolves to the existing contact rather than creating a duplicate
RepliesReplying in a conversation resolves the recipient from the conversation's own contact method -- BSUID contacts need no special handling
Wire formatSendSeven detects a BSUID by its shape and sends it in WhatsApp's Business-scoped-ID recipient field instead of the phone-number field
ID rotationWhatsApp can reissue a person's BSUID. When it does, SendSeven re-points the stored method to the new value, so the contact stays reachable and its ID in your system does not change
Phone revealIf a BSUID-only contact later shares their phone number, it is attached to that contact -- and if the number already belonged to a separate contact record, the two are merged and a contact.updated webhook is sent for the survivor
Username changesA new public username refreshes the method's display_name

About the phone-reveal merge

When a BSUID-only contact shares their phone number and that number already exists on a different contact, the records are the same person: they existed under a phone number before they adopted a username. SendSeven merges them, and the observable result is:

  • The BSUID contact survives as the primary record and keeps its contact ID.
  • The other record's ID keeps resolving: GET /contacts/{old_id} returns the survivor with a merged_from object and an X-Merged-Into response header. See Old UUID Resolution.
  • Field data is preserved by the normal merge rules -- a non-empty value beats an empty one.
  • Conversations, notes, tags and subscriptions move to the survivor.

If you subscribe to contact.updated, the merge is pushed to you: the survivor's event carries a merge object whose merged_from array lists the absorbed contact IDs, so you can re-point your own records without polling. There is no separate "contacts merged" event type and no contact.deleted for the absorbed record. See Merged contacts.

If you are not subscribed, nothing breaks: old IDs keep resolving through GET /contacts/{id} with the X-Merged-Into header.

Only a number the sender shares about themselves is linked. If someone forwards you a third party's contact card, that number is never attached to the sender.

What You Need to Change

1. Stop treating a missing phone number as bad data

A WhatsApp contact with "phone": null and no whatsapp_id is normal. Validation that rejects such records, alerts on them, or "repairs" them by copying another field will corrupt real contacts.

2. Read WhatsApp identifiers from contact_methods[]

The top-level phone and email fields are convenience denormalizations of the primary phone/email methods. They will never contain a BSUID. To find how a contact is reachable on WhatsApp, look for whatsapp_id and whatsapp_bsuid entries:

curl -X GET "https://api.sendseven.com/api/v1/contacts/contact_d4e5f6a7/methods?method_type=whatsapp_bsuid" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00"

3. Fix "one WhatsApp identifier per contact" logic

A contact can hold, at the same time:

  • a whatsapp_id (their phone-shaped WhatsApp ID), and
  • one whatsapp_bsuid per WhatsApp channel they have messaged.

Matching or dedupe logic that keys on a single WhatsApp value will pick an arbitrary one. Key on the whole triple instead: method_type + value + channel_id. Two whatsapp_bsuid values on different channels are not duplicates, and two identical BSUID values on different channels are the same person, not one record to collapse.

4. Handle the new method_type in webhook payloads

whatsapp_bsuid appears anywhere a contact method appears:

  • in contact.contact_methods[] on every event that carries a contact,
  • as the top-level contact_method object on message events, identifying the exact identifier the message used.

Two things break naive consumers:

  • A method_type value your switch/match has never seen. Make the default branch pass the record through rather than drop or reject it.
  • A non-null channel_id on a WhatsApp method. Previously only Messenger and Instagram methods carried one.

See Webhook Events.

5. Sending to a BSUID

Nothing changes for replies -- send with conversation_id and the recipient is resolved for you. When you address a recipient explicitly:

You haveSend with
A conversationconversation_id (recommended -- no identifier handling at all)
A stored contact methodcontact_method_id
A raw BSUIDto = the BSUID plus channel_id of the WhatsApp channel it belongs to
A contact onlycontact_id (+ channel_id) -- the phone-shaped ID is preferred, and the BSUID is used when that is all the contact has
curl -X POST "https://api.sendseven.com/api/v1/messages" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"to": "US.13491208655302741918",
"channel_id": "ch_123",
"contact_id": "contact_d4e5f6a7",
"text": "Your order has shipped."
}'

Pass the value verbatim. SendSeven recognizes the shape, chooses the right recipient field for WhatsApp, and stores the value as a whatsapp_bsuid method on the contact scoped to channel_id -- so later sends can use contact_method_id instead.

For templates, the whatsapp_id request field accepts a BSUID and contact_method_id accepts a whatsapp_bsuid method. See Send a Template Message.

6. Do not move BSUIDs between systems

A BSUID is meaningful only to the WhatsApp Business portfolio that issued it and the channel it is bound to. It is not a phone number, not portable to another provider, and not usable to reach the same person on SMS, RCS, or a voice call. Exports include a whatsapp_bsuid column for reference only -- there is no import column for it, and copying a value onto a different channel produces an address that fails.

7. Ask for a phone number when you genuinely need one

If a workflow requires a real phone number -- shipping SMS, a voice callback, identity checks -- you have to ask. WhatsApp provides a purpose-built prompt: an interactive message of type request_contact_info, whose single button asks the recipient to share their own number. When they tap it, the number is linked (or merged) onto the contact automatically. See WhatsApp Interactive Messages.

Migration Checklist

  • Nothing rejects, alerts on, or "repairs" a WhatsApp contact with no phone number.
  • WhatsApp reachability is read from contact_methods[], not from contact.phone.
  • Dedupe and matching key on method_type + value + channel_id.
  • Unknown method_type values pass through your webhook consumer instead of failing it.
  • channel_id may be non-null on a WhatsApp contact method.
  • No phone-number cleanup or normalization runs over BSUID values.
  • Storage for identifier values allows at least 255 characters.
  • Sends use conversation_id or contact_method_id where possible; raw BSUIDs are always paired with channel_id.
  • Workflows that truly need a phone number ask for one instead of assuming it.

FAQ

Do I have to do anything for contacts who have not adopted a username? No. They keep their phone number and their whatsapp_id method, and they additionally gain a whatsapp_bsuid method. Existing sends keep working unchanged.

Will my existing contacts get duplicated? No. An inbound BSUID resolves to the contact it belongs to and is added as an additional method.

Is a BSUID permanent? It is stable enough to be your long-term handle for that person, but WhatsApp can reissue it. SendSeven re-points the stored method when that happens, so the contact ID you hold does not change. Do not build logic that treats the BSUID string itself as an immutable key in your own database -- key on the SendSeven contact ID.

Can I look someone up by their WhatsApp username? No. Usernames are not addressable and not searchable through any API. SendSeven shows the username on the method's display_name when WhatsApp provides it.

Can I send a template to a BSUID? Yes, with one exception: authentication templates are rejected for Business-scoped recipients, because their one-tap, zero-tap and copy-code buttons require a phone number. Deliver the code with a non-authentication template, or over another channel once you have a number.

Can I start a brand-new conversation with a BSUID I got from somewhere else? Only if the ID was issued to your own WhatsApp Business portfolio and you send from a channel in it. BSUIDs from another business, or from a different portfolio, will not deliver.

Will a BSUID contact count against the 24-hour messaging window differently? No. The window rules are unchanged -- see 24-Hour Messaging Window.

What happens to the second contact record after a phone reveal merge? Its ID keeps resolving to the survivor with a merged_from object and an X-Merged-Into header. If you subscribe to contact.updated, you also get pushed the survivor's event with merge.merged_from naming the absorbed ID. Update your stored reference either way.

Next Steps