feat: support recipient BSUIDs on WhatsApp status webhooks (6.4.0) - #284
Open
ccaseypusher wants to merge 3 commits into
Open
feat: support recipient BSUIDs on WhatsApp status webhooks (6.4.0)#284ccaseypusher wants to merge 3 commits into
ccaseypusher wants to merge 3 commits into
Conversation
Meta's parent business-scoped user ID rollout adds two identifiers our
webhooks now forward, neither of which the SDK could express.
- ConversationSenderMetadata gains parentUserId, the sender's parent
BSUID (from Meta's messages[].from_parent_user_id).
- ConversationRecipientMetadata is new, modelling
status.metadata.recipient.{userId,parentUserId}. Status payloads did
not carry the recipient's own identity before — messageMetadata.to is
only an echo of the address the customer addressed — so this is the
first way to learn a contact's BSUID from a status webhook.
- ConversationStatusMetadata is new, modelling the enclosing
status.metadata block. pricing and conversation stay raw maps: they
are near-verbatim passthroughs of Meta's objects and keep their
snake_case keys, while recipient is ours and is camelCase. Unmodelled
keys (e.g. biz_opaque_callback_data) are collected rather than dropped.
Both new types parse under a plain ObjectMapper, so consumers need not
disable FAIL_ON_UNKNOWN_PROPERTIES. recipient is absent from payloads
for accounts that receive no BSUIDs, and deserialises to null there.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The payload types added in 6.3.0 are meant to be deserialized by consumers in their own HTTP handlers, but only parsed under a mapper with FAIL_ON_UNKNOWN_PROPERTIES disabled — which the SDK's internal mapper does and a plain ObjectMapper does not. A consumer following the javadoc got an UnrecognizedPropertyException, and would get one again every time the platform adds a field to a payload they already parse. Adds @JsonIgnoreProperties(ignoreUnknown = true) to the four types on the status payload path: ConversationStatusMessageMetadata, ConversationMessageMetadata, ConversationSenderMetadata and ConversationContent. This matches the new types added alongside it and makes the webhook-parsing story uniform. Deserialization only loosens, so nothing that parsed before stops parsing; serialization is untouched, which the existing send-request tests cover. The 6.3.0 test no longer needs to disable the feature by hand, and a new test parses a payload carrying unknown keys at every nesting level under a plain mapper. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ccaseypusher
force-pushed
the
feat/whatsapp-recipient-parent-user-id
branch
from
July 31, 2026 11:25
9456fc8 to
4f1152d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Meta added parent business-scoped user IDs to the WhatsApp Cloud API webhook payloads as part of the BSUID rollout. Our API now forwards them; this models them in the Java SDK.
from_parent_user_idmessages[]metadata.sender.parentUserIdConversationSenderMetadata.getParentUserId()recipient_user_idstatuses[]status.metadata.recipient.userIdConversationRecipientMetadata.getUserId()recipient_parent_user_idstatuses[]status.metadata.recipient.parentUserIdConversationRecipientMetadata.getParentUserId()Why
recipient.userIdis here tooStatus webhooks did not expose the recipient's identity at all —
messageMetadata.tois only an echo of the address the customer sent to. Forwarding the parent alone would hand customers a parent identifier with no base BSUID beside it, so both ship together. It also closes a real gap: a customer who addressed a phone number had no way to learn that contact's BSUID, which matters ahead of the June 2026 change where phone numbers may stop being present.Shape
{ "type": "statusDelivered", "status": { "metadata": { "pricing": { "...": "unchanged" }, "conversation": { "...": "unchanged" }, "recipient": { "userId": "US.13491208655302741918", "parentUserId": "US.ENT.11815799212886844830" } } } }Nested rather than flat, mirroring
message.metadata.sender.{userId,parentUserId}on the inbound side.Commits
1.
feat:model recipient BSUIDs on WhatsApp status webhooksConversationStatusMetadatais new and models the enclosingstatus.metadatablock, which the SDK had no type for.pricingandconversationare exposed as rawMap<String, Object>— they are near-verbatim passthroughs of Meta's own objects and keep their snake_case keys (pricing_model,country_code), so modelling them would couple us to Meta's schema.recipientis ours and follows our camelCase convention. That makes the object mixed-case; nesting under onerecipientkey contains the inconsistency to a single place.biz_opaque_callback_data) lands ingetAdditionalProperties()via@JsonAnySetter.2.
fix:tolerate unknown fields on webhook payload POJOsThe payload types added in 6.3.0 are documented for consumers to deserialize in their own HTTP handlers, but only parsed under a mapper with
FAIL_ON_UNKNOWN_PROPERTIESdisabled — which the SDK's internal mapper does and a plainObjectMapperdoes not. A consumer following the javadoc got anUnrecognizedPropertyException, and would get one again every time the platform added a field to a payload they already parse.@JsonIgnoreProperties(ignoreUnknown = true)is added to the four types on the status payload path:ConversationStatusMessageMetadata,ConversationMessageMetadata,ConversationSenderMetadataandConversationContent. The 6.3.0 test no longer disables the feature by hand, and a new test parses a payload carrying unknown keys at every nesting level under a plain mapper.Not breaking:
ignoreUnknownonly loosens deserialization, so nothing that parsed before stops parsing, and serialization is untouched — the existing send-request tests cover that. Scope is the status payload path; deeper content sub-objects (hsm,email, media) are not on it and are unchanged.3.
chore(release):bump version to 6.4.0Backward compatibility
recipientis omitted entirely from payloads for accounts that never receive BSUIDs, and deserialises tonullthere — covered by a dedicated test. All additions are new getters/setters on existing POJOs plus two new classes; nothing existing changes shape.Deliberately out of scope
contacts[].parent_user_id— the sender's parent BSUID is read from the messages object, mirroring howfrom_user_idis read, so a contacts field would be an unread member.recipient_participant_user_id,recipient_participant_parent_user_id) — this SDK has no WhatsApp group support.{type, status}) is still unmodelled, consistent withConversationStatusMessageMetadataadded in 6.3.0: these are standalone POJOs for consumers parsing sub-objects of their own webhook bodies.Verification
mvn -Ptest testmvn -Ptest packageNote this repo has no GitHub Actions — only a legacy
.travis.yml— so no checks run on this PR. The above was run locally.Version bumped to 6.4.0 in
api/pom.xmlandexamples/pom.xml(additive, no breaking changes).🤖 Generated with Claude Code