Event types
Only
whatsapp.received is new incoming content. Delivery notifications update the original message’s tracking; do not wake an agent to reply or automatically resend because one arrives. Preserve the originating identity and conversation when routing a reply.
Subscribe
scope=identity when updating or deleting a mixed subscription. Disabling WhatsApp preserves other selected notification families. Current identity availability and permissions still control delivery.
Payload
Every event uses the standard envelope with stableid, event_type, ISO timestamp, and data. Deduplicate retries by the event ID, not just the message text or phone number.
data.message uses the webhook-specific WhatsApp message shape. Unlike the REST response, it omits is_blocked and status_refresh_pending entirely; these fields are not null placeholders. Use the SDK webhook message type, not a strict REST message schema. It otherwise follows the WhatsApp message object: content, stable message and conversation IDs, original local number, actual sender_number, remote-only participants, and explicit send/delivery state. data.contacts and data.agent_identities carry the permission-filtered peer matches where available.
Group messages use the same events. Check data.message.is_group and group_name, then route replies with conversation_id, not the name. remote_number is null for groups; sender_number can be null when the author’s number is unavailable. Quoted replies and media retain their normal message fields. Receiving a reaction does not satisfy a group’s incoming-message prerequisite. For group events, data.contacts and data.agent_identities are empty. Message events identify the message author with data.message.sender_number; reaction events identify the reactor with data.reaction.remote_number, which can be null. Never substitute the target message’s author for an unknown reactor.
Media entries preserve their stable ID, filename, MIME type, nullable size, availability and nullable temporary URL. Treat unavailable bytes explicitly. Refresh an expired URL with GET /whatsapp/media/{id}, not by re-sending or re-uploading the message.
Group mentions
A native group mention arrives as the existingwhatsapp.received event. data.message.agent_mentioned is a boolean that defaults to false when absent. There is no separate mention event or subscription.
To mention the agent, type @ in WhatsApp and select the agent from the normal mention picker. Do not parse raw transport identifiers from message text to detect mentions. Use agent_mentioned for native mention detection.
In a compatible agent integration’s mention-only group reply mode, a native mention or a literal @agent-handle can trigger a reply. Other group messages remain conversation context without requiring a reply. This reply policy does not change the event type or bypass group send permissions.
Other mentioned participants
data.message.mentions describes native mentions in the current incoming message, including direct chats and groups. It defaults to []. Each entry contains:
text: the matching visible mention token, ornullwhen unavailable.phone_number: the participant’s E.164 number when a mapping is available and visible to the agent, ornullotherwise.is_agent: whether this mention refers to the receiving agent.
whatsapp.received event can contain this message excerpt:
phone_number with your existing contact lookup if you need a saved contact name. Do not invent names or treat raw transport identifiers as phone numbers. Mentions of other participants provide conversation context; they do not trigger a group reply in mention-only mode. Direct chats do not require a mention to receive a reply.
Update direct-only consumers
Existing message and conversation lists andwhatsapp.received subscriptions can include group conversations. Upgrade SDK/CLI consumers to 0.7.29 or later before processing group responses. Older strict clients can fail to parse an entire message or conversation list when just one entry is a group, as well as individual group reads and webhook payloads. Handle is_group, nullable remote_number, and nullable sender_number; do not assume every event has one remote phone number. Route group replies by conversation_id.
Companion admission
A sponsored group message can includesender_access: "sponsored" and top-level companion metadata. The same identity preference, sponsor rules, initialization history, and revocation contract apply as for other supported channels. Preserve receipt-time admission and the current activation through retries; do not infer admission from the event phase. See per-message sender access.
Conversation context
whatsapp.received can use the existing texts class in the subscription’s context configuration. Context items identify their actual channel, including whatsapp. Delivery-only events do not represent another incoming-message turn.
WhatsApp does not add a new context class. Existing whatsapp.received events can carry the top-level Companion metadata for a sponsored group. Subscribe and route only the event types your runtime handles.
Group received-message context stays within that group; it does not merge a member’s direct-message, SMS, or iMessage history.
WhatsApp enters texts context only for a whatsapp.received trigger. Email, SMS, and iMessage triggers retain their existing context behavior, even when the same subscription also selects WhatsApp events.
Reaction events
whatsapp.reaction_received carries data.reaction plus the original target in data.message; the target is not a new incoming message. Its value is a reaction receipt, including the target message, direction, nullable actor number, revision, and status. A removal uses status: "removed". Deduplicate by event ID and retain version ordering for the same actor and target message; do not reapply an older reaction after a newer revision. Unknown actor numbers remain null.
Message events preserve data.message with quote/thread IDs and currently applied reactions. A reaction or delivery event must not start a new text-reply turn unless your application deliberately handles that event type.
