Skip to content

feat: WhatsApp BSUID support in Messages API (DEVX-11482) - #627

Open
dragonmantank wants to merge 2 commits into
mainfrom
DEVX-11482-whatsapp-bsuid-support
Open

feat: WhatsApp BSUID support in Messages API (DEVX-11482)#627
dragonmantank wants to merge 2 commits into
mainfrom
DEVX-11482-whatsapp-bsuid-support

Conversation

@dragonmantank

Copy link
Copy Markdown
Member

Summary

Adds support for WhatsApp business-scoped user IDs (BSUIDs) to the Messages API. When a WhatsApp user adopts a username, Meta may identify them by a BSUID instead of (or in addition to) a phone number. This PR lets the SDK send to BSUID recipients and parse the new BSUID fields on inbound messages and status callbacks.

Reference: Handling WhatsApp Usernames and BSUIDs

Changes

Outbound (send)

  • WhatsApp to now accepts a BSUID or parent BSUID as well as an E.164 phone number.
  • New Bsuid validation helper — format {ISO alpha-2}.{≤128 alphanumeric} (e.g. US.13491208655302741918) and parent BSUID {CC}.ENT.{id} (e.g. US.ENT.11815799212886844830).
  • WhatsappRequest recipient validation relaxed via sanitizeRecipient() (accepts E.164 or BSUID); from remains E.164.

Inbound webhook

  • New whatsapp.sender object exposed via InboundMessage.getWhatsappSender().
  • Profile.getUsername() added.

Status callback

  • New whatsapp.recipient object exposed via MessageStatus.getWhatsappRecipient().
  • WhatsApp profile exposed via MessageStatus.getWhatsappProfile() (includes username).

Shared model

  • New WhatsappUser (user_id = BSUID, parent_user_id = parent BSUID, wa_id = phone number) used by both whatsapp.sender and whatsapp.recipient.

Tests

  • New BsuidTest (valid/parent/max-length/malformed/null cases).
  • BSUID send + parent BSUID + sender-cannot-be-BSUID + invalid-recipient cases in WhatsappTextRequestTest.
  • whatsapp.recipient + profile.username parsing in MessageStatusTest.
  • whatsapp.sender + profile.username parsing in InboundMessageTest.
  • All 332 messages-package tests pass; a full mvn test run passed (1465 tests, 0 failures).

Notes

  • @since tags use 9.13.0 (next version after the released 9.12.0). pom.xml version bump not included — assumed handled at release time via bumpversion.sh.
  • BSUIDs cannot be used for one-tap/zero-tap/copy-code auth templates (server-enforced, error 131062); documented in the builder Javadoc, not enforced client-side.

WhatsApp users who adopt a username are identified by a business-scoped
user ID (BSUID) instead of, or in addition to, a phone number.

- Outbound: WhatsApp 'to' now accepts a BSUID or parent BSUID as well as
  a phone number (new Bsuid validation helper; WhatsappRequest recipient
  validation relaxed accordingly).
- Inbound: added whatsapp.sender via InboundMessage.getWhatsappSender()
  (shared WhatsappUser model: user_id/parent_user_id/wa_id).
- Status: added whatsapp.recipient via MessageStatus.getWhatsappRecipient()
  and WhatsApp profile via getWhatsappProfile().
- Profile: added getUsername().
@codecov-commenter

codecov-commenter commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.05%. Comparing base (206526c) to head (ec18840).

Additional details and impacted files
@@            Coverage Diff            @@
##               main     #627   +/-   ##
=========================================
  Coverage     99.05%   99.05%           
- Complexity     3643     3656   +13     
=========================================
  Files           548      549    +1     
  Lines          8052     8068   +16     
  Branches        445      446    +1     
=========================================
+ Hits           7976     7992   +16     
  Misses           56       56           
  Partials         20       20           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@superchilled superchilled left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. My only question is whether we maybe want to be more permissive wrt the to field, e.g. allow any string input regardless of format. The current logic of sanitizeRecipient checks if the input is either in E.164 format or matches the defined regex for BSUID format.

This is fine given the current known parameters of what can be specified as the recipient for a WhatsApp message, but:

  1. We know from previous experience that Meta has a habit of regularly changing their API and definitions, so the current BSUID format may be subject to change in the future
  2. Other valid formats for the to field will require support in the future. For example, we already know that WhatsApp group messaging is on the Messages API product roadmap, and the group ID again has a different format

Per review feedback: validating 'to' against a client-side BSUID regex
risks rejecting recipients that Meta accepts if they loosen the format,
forcing an urgent SDK release. Instead, normalise E.164 phone numbers and
pass any other non-empty recipient (e.g. a BSUID) through unchanged; the
API validates and rejects genuinely unsupported values (error 131062).

Removes the Bsuid validation class and its test.
@dragonmantank

Copy link
Copy Markdown
Member Author

Updated per review feedback (commit ec188406):

Dropped the bespoke Bsuid format validation on to. Rationale: a strict client-side regex risks rejecting recipients that Meta actually accepts whenever they loosen their format, which would force an urgent SDK release.

New behaviour for WhatsApp to:

  • If it parses as an E.164 phone number, it's normalised (existing behaviour — strips spaces/dashes/leading +).
  • Any other non-empty value (e.g. a BSUID, or a future provider format) is passed through unchanged.
  • null/empty are still rejected; from is still strictly E.164.

The API validates the recipient and returns error 131062 for genuinely unsupported values, so we lose nothing by not duplicating that check client-side. Removed Bsuid.java/BsuidTest.java; added passthrough + normalisation tests. All 328 messages-package tests pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants