Skip to content

Add BSUID support#245

Merged
aalbarca merged 1 commit into
mainfrom
bsuid-support
Apr 14, 2026
Merged

Add BSUID support#245
aalbarca merged 1 commit into
mainfrom
bsuid-support

Conversation

@aalbarca

Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds Business‑Scoped User ID (BSUID) support across outbound message sending (via a new optional recipient field) and improves webhook customer identification by supporting user_id/parent_user_id in inbound payloads.

Changes:

  • Add optional BSUID recipient support to Message/MessageRequest and most WhatsAppCloudApi::send*() methods.
  • Refactor message request bodies to share common fields (to/recipient/context) via MessageRequest::build().
  • Extend webhook Customer to support user_id (BSUID) and add tests/docs for BSUID scenarios.

Reviewed changes

Copilot reviewed 44 out of 44 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Unit/WhatsAppCloudApiTest.php Updates existing unit tests for new method signatures and adds recipient-only send tests + missing-recipient validation test.
tests/Unit/WebHook/NotificationFactoryTest.php Adds tests for BSUID-only webhook payloads and WA ID precedence when both IDs exist.
tests/Integration/WhatsAppCloudApiTest.php Updates integration tests to match the new sendContact() signature.
src/WhatsAppCloudApi.php Adds optional recipient parameter across send methods and wires it into message objects.
src/WebHook/Notification/Support/CustomerIdType.php Introduces a small type wrapper for customer identifier type (wa_id vs user_id).
src/WebHook/Notification/Support/Customer.php Expands customer identity model to include WA ID vs BSUID and additional profile fields.
src/WebHook/Notification/MessageNotificationFactory.php Populates the extended Customer model from webhook payloads (including BSUID fields).
src/Request/MessageRequest/RequestVideoMessage.php Switches to shared request-body builder and then adds video-specific payload.
src/Request/MessageRequest/RequestTextMessage.php Switches to shared request-body builder and then adds text-specific payload.
src/Request/MessageRequest/RequestTemplateMessage.php Switches to shared request-body builder and then adds template-specific payload.
src/Request/MessageRequest/RequestStickerMessage.php Switches to shared request-body builder and then adds sticker-specific payload.
src/Request/MessageRequest/RequestSingleProductMessage.php Switches to shared request-body builder and then adds single-product payload.
src/Request/MessageRequest/RequestReactionMessage.php Switches to shared request-body builder and then adds reaction-specific payload.
src/Request/MessageRequest/RequestOptionsListMessage.php Switches to shared request-body builder and then adds list-interactive payload.
src/Request/MessageRequest/RequestMultiProductMessage.php Switches to shared request-body builder and then adds multi-product payload.
src/Request/MessageRequest/RequestLocationRequestMessage.php Switches to shared request-body builder and then adds location-request interactive payload.
src/Request/MessageRequest/RequestLocationMessage.php Switches to shared request-body builder and then adds location-specific payload.
src/Request/MessageRequest/RequestImageMessage.php Switches to shared request-body builder and then adds image-specific payload.
src/Request/MessageRequest/RequestDocumentMessage.php Switches to shared request-body builder and then adds document-specific payload.
src/Request/MessageRequest/RequestCtaUrlMessage.php Switches to shared request-body builder and then adds CTA URL interactive payload.
src/Request/MessageRequest/RequestContactMessage.php Switches to shared request-body builder and then adds contact payload.
src/Request/MessageRequest/RequestCatalogMessage.php Switches to shared request-body builder and then adds catalog interactive payload.
src/Request/MessageRequest/RequestButtonReplyMessage.php Switches to shared request-body builder and then adds button-interactive payload.
src/Request/MessageRequest/RequestAudioMessage.php Switches to shared request-body builder and then adds audio-specific payload.
src/Request/MessageRequest.php Adds centralized body()/build() to include to/recipient and reply context consistently.
src/Message/VideoMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/TextMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/TemplateMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/StickerMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/SingleProductMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/ReactionMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/OptionsListMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/MultiProductMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/Message.php Adds recipient field and enforces that at least one of to/recipient is provided.
src/Message/LocationRequestMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/LocationMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/ImageMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/DocumentMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/CtaUrlMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/ContactMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/CatalogMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/ButtonReplyMessage.php Allows nullable $to and threads optional $recipient into the base Message.
src/Message/AudioMessage.php Adds recipient support to audio messages (but with a different parameter order vs other message types).
README.md Documents how to use BSUID recipient support and updates sendContact() example usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/WhatsAppCloudApi.php
Comment on lines +294 to +296
public function sendContact(?string $to, ContactName $name, ?string $recipient = null, Phone ...$phone): Response
{
$message = new Message\ContactMessage($to, $name, $this->reply_to, ...$phone);
$message = new Message\ContactMessage($to, $name, $this->reply_to, $recipient, ...$phone);

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

sendContact() is now a breaking change for existing callers: the third positional argument used to be the first Phone, but it is now ?string $recipient, so calls like sendContact($to, $name, $phone) will throw a TypeError. To keep backward compatibility, consider avoiding inserting a new parameter before the variadic (e.g., introduce a new method for BSUID contacts, or accept a union for the 3rd argument and detect whether it's a Phone vs recipient string, shifting arguments accordingly).

Copilot uses AI. Check for mistakes.
Comment on lines +24 to 29
public function __construct(?string $to, MediaID $id, ?string $recipient, ?string $reply_to)
{
$this->id = $id;

parent::__construct($to, $reply_to);
parent::__construct($to, $recipient, $reply_to);
}

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

AudioMessage’s constructor parameter order and defaults are inconsistent with the other Message subclasses (recipient is required in the signature and comes before $reply_to). This makes it easy to accidentally swap $recipient/$reply_to and is also a backwards-incompatible change for anyone instantiating AudioMessage directly. Consider aligning it with the common pattern used elsewhere (e.g., $reply_to first, and $recipient optional at the end).

Copilot uses AI. Check for mistakes.
Comment thread src/WhatsAppCloudApi.php
Comment on lines 73 to +77
* @param bool Determines if show a preview box for URLs contained in the text message.
*
* @throws Response\ResponseException
*/
public function sendTextMessage(string $to, string $text, bool $preview_url = false): Response
public function sendTextMessage(?string $to, string $text, bool $preview_url = false, ?string $recipient = null): Response

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

The PHPDoc for sendTextMessage() no longer matches the method signature: $to is now nullable and there is a new optional $recipient parameter, but the docblock still documents only the old parameters. Please update the docblock to reflect the new signature so IDEs/static analysis and generated docs stay accurate.

Copilot uses AI. Check for mistakes.
@aalbarca aalbarca merged commit 74d08dd into main Apr 14, 2026
15 of 17 checks passed
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.

2 participants