Skip to content
Start free

WhatsApp usernames & user IDs

Meta now identifies WhatsApp users with a Business Scoped User ID (BSUID). This ID is scoped to the business portfolio that owns your WhatsApp number and is the identity Wabery exposes as user_id. A phone number is an optional address, not the contact key. Current BSUIDs use the complete CC.<alphanumeric> form (or CC.ENT.<alphanumeric> for an enabled parent BSUID) and must not be truncated or reformatted.

Wabery uses the Meta business-portfolio owner ID as the namespace when embedded signup captured it. Older channels without that metadata use an explicit WABA namespace as a fail-closed fallback; Wabery never broadens a BSUID to an entire Wabery organization.

No new Wabery API version is required: no existing endpoint or webhook field is removed or renamed. Existing phone-number conversations keep the same contact_id, conversation_id, and E.164 from behavior. Wabery’s existing public to input remains an E.164 phone-number input. For sends addressed by conversation_id, Wabery resolves the stored contact: it maps a known phone to Meta’s to field and a phone-hidden BSUID to Meta’s dedicated recipient field. Wabery continues to prefer the phone value whenever one is known.

However, this is still a required compatibility update for webhook consumers. A username user may not expose a phone number, and Meta can rotate their BSUID. Before rollout, make sure your integration:

  • accepts from: null and recipient_id: null instead of requiring E.164;
  • joins records on contact_id, not from or a raw BSUID;
  • accepts additive webhook properties and safely acknowledges unknown event and message types;
  • handles contact.identity.updated, or at minimum does not reject it; and
  • requests contact info before a phone-only workflow such as an authentication template.

The existing fields remain in place:

  • from is the E.164 phone number when Meta discloses it, otherwise null.
  • user_id is the WhatsApp BSUID when Meta supplies one and is safe inside the channel’s business portfolio.
  • parent_user_id and username are nullable metadata from Meta.
  • contact_id remains Wabery’s stable application-facing contact identifier.
  • message.status can include recipient_user_id even when no phone is known.

Wabery consumes Meta’s required user_id_update webhook and emits contact.identity.updated after reconciling a changed BSUID. Store the new user_id if you mirror platform identities, but keep joining on contact_id. These nullable identity properties already exist in Wabery’s webhook shape; the rollout populates them when Meta supplies the corresponding values.

{
"event": "contact.identity.updated",
"payload": {
"object": "contact_identity",
"channel_id": "channel_...",
"contact_id": "contact_...",
"previous_user_id": "US.111",
"user_id": "US.222",
"parent_user_id": null,
"phone": null,
"updated_at": "2026-08-05T12:00:00.000Z"
}
}

Send an interactive contact-info request inside the customer-service window:

await wabery.messages.send({
channelId: "channel_...",
conversationId: "conversation_...",
interactive: {
type: "request_contact_info",
body: { text: "Share your number so we can complete your booking." },
},
});

The response arrives as messages[n].type: "contacts" and the complete contact cards are in messages[n].contacts. Wabery only backfills the sender phone when Meta marks the card with origin: "contact_request"; ordinary shared contacts never change the sender’s identity. Meta’s one-tap, zero-tap, and copy-code authentication templates still require a phone-number recipient.

Templates can include Meta’s fixed contact button:

{
"type": "BUTTONS",
"buttons": [{ "type": "REQUEST_CONTACT_INFO", "text": "Share Contact Info" }]
}

Business usernames make a business discoverable; they do not hide the business phone number.

Meta allows 3–35 characters: English letters, digits, periods, and underscores, with at least one letter. A username cannot start or end with a period, contain two consecutive periods, start with www, or end with a domain suffix. Matching is case-insensitive; periods and underscores remain distinct.

const suggestions = await wabery.channels.listWhatsAppUsernameSuggestions("channel_...");
const username = await wabery.channels.setWhatsAppUsername("channel_...", {
username: "AcmeSupport",
// Only use this when moving the username from another number in this portfolio:
transferAction: "none",
});

Use GET, POST, or DELETE /v1/channels/{id}/whatsapp-username. The current status is approved (visible) or reserved (claimed but not visible yet). transfer_action defaults to none; use force_transfer only to move a username already assigned to another phone number in the same portfolio. Meta removed pending-request cancellation from the current contract. Wabery emits channel.username.updated when Meta sends business_username_updates. The event status is approved, reserved, or deleted.

{
"event": "channel.username.updated",
"payload": {
"object": "whatsapp_username",
"channel_id": "channel_...",
"username": "AcmeSupport",
"status": "approved",
"updated_at": "2026-08-05T12:00:00.000Z"
}
}

Meta is authoritative for availability, eligibility, linked Facebook/Instagram requirements, and status. See Meta’s official Business Scoped User IDs documentation.