Inbox webhooks
Receive an event for every DM, delivery receipt, reaction, comment and review that reaches the inbox, and know which platforms send which.
Inbox events cover everything that lands in or leaves the inbox: DMs and their delivery lifecycle, conversations, emoji reactions, comments on tracked posts, and reviews. Subscribe with POST /v1/webhooks/settings and the event names below (first event); delivery, retries and signatures are the same for every event (how webhooks behave). Message payloads carry an account block with accountId and profileId, so one endpoint can serve many profiles.
Events
| Event | Description |
|---|---|
message.received | A new inbox message arrived. |
message.sent | An outgoing message was sent from the inbox. |
conversation.started | A new conversation began between an account and a contact, on any DM platform. Once per conversation. |
conversation.control_changed | Meta's handover protocol moved a conversation: Meta Business Agent or a partner app on WhatsApp, another app such as Page Inbox on Facebook and Instagram. |
message.edited | A sender edited a previously sent message. |
message.deleted | A sender deleted (unsent) a message. |
message.delivered | An outgoing message was delivered to the recipient. |
message.read | An outgoing message was read by the recipient. |
message.failed | An outgoing message failed to deliver (WhatsApp, SMS). |
reaction.received | A participant added or removed an emoji reaction (Instagram, Facebook, WhatsApp, Telegram, Slack, TikTok). |
referral.received | Someone opened an existing Instagram or Messenger conversation through an ig.me or m.me ref link or a returning Messenger ad click. |
comment.received | A new comment arrived on a tracked post. |
review.new | A new review was posted on a connected account. |
review.updated | A review was edited or a reply was added. |
How it behaves
Not every platform sends every event
Zernio forwards what each platform exposes:
| Event | Platforms |
|---|---|
message.edited | Instagram, Facebook Messenger, Telegram, WhatsApp |
message.deleted | Instagram (incoming unsend), WhatsApp (both directions) |
message.delivered | WhatsApp, Facebook Messenger, SMS |
message.read | WhatsApp, Facebook Messenger, Instagram |
message.failed | WhatsApp, SMS |
conversation.control_changed | WhatsApp, Facebook Messenger, Instagram |
reaction.received | Instagram, Facebook, WhatsApp, Telegram, Slack, TikTok |
referral.received | Instagram, Facebook Messenger |
review.new, review.updated | Google Business Profile |
conversation.started covers every DM platform (Instagram, Messenger, Telegram, WhatsApp, X, Reddit, Bluesky) with one event.
A legacy AppSumo plan gates the inbox
Every event on this page except conversation.control_changed needs inbox access. Without it POST /v1/webhooks/settings refuses the subscription itself with a 403 and code feature_not_available, rather than accepting it and delivering nothing. A legacy AppSumo plan keeps the inbox off until support enables it (pricing).
Pre-connect history fires nothing
When an Instagram or Facebook account connects, Zernio replays the DM history it already holds on Meta into the inbox. That replayed history emits neither conversation.started nor message.received. This is the opposite of the post backfill, where every pre-existing native post is reported. Read replayed DMs from List inbox conversations; they are stored as already read, so they never affect unread counts.
Reactions arrive as their own event
Zernio sends reaction.received as its own event, never as message.received, so branch on it separately and a thumbs-up is never treated as an inbound DM. reaction.action is added or removed. reaction.platformMessageId is the platform-native id of the reacted-to message and is always present; reaction.messageId is the Zernio message id when it can be resolved. On WhatsApp, Instagram and Facebook removals the platform does not report which emoji went away, so reaction.emoji is an empty string when action is removed: match on platformMessageId to clear a reaction you mirror. TikTok sends no unicode for an AI emoji reaction, so reaction.emoji can be empty for those too.
Another app can own the conversation (standby)
Meta's handover protocol lets one app answer a conversation while the others only observe. Zernio still delivers every inbound message as message.received, flagged metadata.standby: true, and runs no automation on it: no workflow, no keyword automation.
- WhatsApp: on a number with Meta Business Agent enabled, the agent answers from Meta's side and its replies arrive as
message.sentwithsource: "meta_business_agent". Sending any message takes control back, so a bot that replies to everymessage.receivedmust skip standby ones or it takes the conversation away from the agent. - Facebook and Instagram: another app on the Page, such as Page Inbox, owns the thread. A send while you are not the owner answers
409with codenot_thread_owner(details.ownerAppIdnames the owner when Meta reports it). Take control first with Change who answers a conversation.
conversation.control_changed tells you when control moves.
WhatsApp status events carry Meta's pricing
On WhatsApp, message.sent, message.delivered, message.read and message.failed carry two extra keys from Meta's status webhook: pricing (billable, pricingModel, category, type) and billingConversation (id, expiresAt, originType). Both keys are always present on WhatsApp and null when Meta left the object out, which it does on most statuses: Meta sends pricing on sent and on one of delivered or read. billingConversation is Meta's billing window, not the Zernio conversation block. The keys are absent on other platforms. For totals over a period, use GET /v1/whatsapp/pricing-analytics (WhatsApp phone numbers).
message.sent names what sent it
message.sent carries message.sentVia (human, api, broadcast, sequence, workflow, comment_automation, bulk-api) and five attribution keys: automationId (the comment automation), workflowId and executionId (the workflow and its run), broadcastId and sequenceId. They are always present: each is null unless that kind of sender produced the message, and on message.received all of them are null. sentVia is null for a message sent from the platform's own app and for messages stored before it shipped, so treat null as unknown, never as "sent by a human". On Instagram and Facebook the attribution can be missing when Meta's echo of a send reaches Zernio before the send itself is recorded.
Interactive replies ride on message.received
Zernio delivers button and list taps, flow responses, orders and referrals that arrive with a message under metadata on message.received (interactiveType, interactiveId, flowResponseData, order, referral). Only a referral that arrives without a message becomes referral.received.
message.received
A new inbox message arrived. message.text, message.attachments[] and message.sender describe it; conversation.id is the conversationId for POST /v1/inbox/conversations/{conversationId}/messages.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for message received events
Response Body
Example Requests
Webhook payload for message received events
/message.receivedmessage.sent
An outgoing message was sent from the inbox, through the API or the dashboard.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for message sent events (fired when a message is sent via the API, or from the WhatsApp Business app on Coexistence numbers)
Response Body
Example Requests
Webhook payload for message sent events (fired when a message is sent via the API, or from the WhatsApp Business app on Coexistence numbers)
/message.sentconversation.started
A new conversation began between one of your connected accounts and a contact, in either direction, on any DM platform. A given conversation fires it once, the first time it appears. Pre-connect history never fires it (why).
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Fired once when a new conversation begins, in either direction. A conversation starts the first time an account and a contact exchange a message on any DM platform (Instagram, Messenger/Facebook, Telegram, WhatsApp, X, Reddit, Bluesky, SMS, TikTok). Platform-agnostic: one subscription covers every DM platform.
Response Body
Example Requests
Fired once when a new conversation begins, in either direction. A conversation starts the first time an account and a contact exchange a message on any DM platform (Instagram, Messenger/Facebook, Telegram, WhatsApp, X, Reddit, Bluesky, SMS, TikTok). Platform-agnostic: one subscription covers every DM platform.
/conversation.startedconversation.control_changed
Control of a conversation moved under Meta's handover protocol (messaging_handovers). control.owner is who answers now: ai_agent (Meta Business Agent, WhatsApp), app (you) or other (a WhatsApp partner app, or a Messenger or Instagram receiver such as Page Inbox); control.previousOwner is who did before, null when no handover had touched the thread. control.ownerAppId is the Meta app id of the new owner when Meta names it (Page Inbox is 263902037430900), and control.metadata is the note the transferring app attached, forwarded verbatim.
- WhatsApp: Meta Business Agent took the conversation over or handed it to you, or another partner app took it. While the owner is
ai_agent, the agent's replies arrive onmessage.sentwithsource: "meta_business_agent". Sending any message through the inbox takes control back; to hand it to the agent without sending, call Change who answers a conversation withaction: "release". - Facebook and Instagram: another app on the Page passed the thread to you, or took or received it. While you are not the owner, sends answer
409not_thread_owner; call Change who answers a conversation withaction: "take", or"request"to ask the owner to pass it. A repeat report of the same owner fires nothing, and arequestchanges nothing until the owner passes the thread.
While another app owns the conversation, inbound messages arrive on message.received with metadata.standby: true.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Who answers a conversation changed under Meta's handover protocol. WhatsApp: Meta Business Agent took it over, handed it to you, or another partner app took it. Facebook and Instagram: another app passed the thread to you, or took or received it.
Response Body
Example Requests
Who answers a conversation changed under Meta's handover protocol. WhatsApp: Meta Business Agent took it over, handed it to you, or another partner app took it. Facebook and Instagram: another app passed the thread to you, or took or received it.
/conversation.control_changedmessage.edited
The sender edited a previously sent message on Instagram, Facebook Messenger, Telegram or WhatsApp. The payload carries the full editHistory, oldest prior version first, and message.text is the latest version.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for message.edited events. Fires when the sender edits a previously-sent message. Supported platforms: Instagram, Facebook Messenger, Telegram, WhatsApp. The message object reflects the LATEST state; editHistory contains every prior version in order (oldest first), so the last entry is the version immediately before the current content.
Response Body
Example Requests
Webhook payload for message.edited events. Fires when the sender edits a previously-sent message. Supported platforms: Instagram, Facebook Messenger, Telegram, WhatsApp. The message object reflects the LATEST state; editHistory contains every prior version in order (oldest first), so the last entry is the version immediately before the current content.
/message.editedmessage.deleted
The sender deleted (unsent) a message: on Instagram an incoming unsend, on WhatsApp in both directions, with message.direction telling the business's deletions from the customer's. The payload keeps the pre-delete text and attachments for moderation, compliance or archival. The Zernio dashboard does not show this content.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for message.deleted events. Fires when the sender
deletes (unsends) a message. Supported platforms: Instagram (incoming
unsend) and WhatsApp, in both directions: an outgoing message the
business deleted (via the Cloud API, or from the WhatsApp Business app
on a Coexistence number) and an incoming message the customer deleted.
Read message.direction to tell the two apart.
The message.text and message.attachments fields retain the content that existed before the delete. The Zernio dashboard UI does not show this content, but authorized API consumers may access it for moderation, compliance, or archival use cases.
Response Body
Example Requests
Webhook payload for message.deleted events. Fires when the sender
deletes (unsends) a message. Supported platforms: Instagram (incoming
unsend) and WhatsApp, in both directions: an outgoing message the
business deleted (via the Cloud API, or from the WhatsApp Business app
on a Coexistence number) and an incoming message the customer deleted.
Read message.direction to tell the two apart.
The message.text and message.attachments fields retain the content that existed before the delete. The Zernio dashboard UI does not show this content, but authorized API consumers may access it for moderation, compliance, or archival use cases.
/message.deletedmessage.delivered
An outgoing message was delivered to the recipient on WhatsApp, Facebook Messenger or SMS.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Shared payload for message.delivered, message.read, message.played and message.failed events. Fires when the platform reports a new delivery state for an outgoing message.
Platform support:
- message.delivered: WhatsApp, Facebook Messenger, SMS, RCS.
- message.read: WhatsApp, Facebook Messenger, Instagram, RCS. Not SMS (carriers report delivery, never read).
- message.played: WhatsApp only, voice messages.
- message.failed: WhatsApp, SMS and RCS (other platforms don't expose
per-message failure via webhook). On SMS,
error.codeis the carrier's numeric code anderror.messageits reason.
Response Body
Example Requests
Shared payload for message.delivered, message.read, message.played and message.failed events. Fires when the platform reports a new delivery state for an outgoing message.
Platform support:
- message.delivered: WhatsApp, Facebook Messenger, SMS, RCS.
- message.read: WhatsApp, Facebook Messenger, Instagram, RCS. Not SMS (carriers report delivery, never read).
- message.played: WhatsApp only, voice messages.
- message.failed: WhatsApp, SMS and RCS (other platforms don't expose
per-message failure via webhook). On SMS,
error.codeis the carrier's numeric code anderror.messageits reason.
/message.deliveredmessage.read
An outgoing message was read by the recipient on WhatsApp, Facebook Messenger or Instagram.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Shared payload for message.delivered, message.read, message.played and message.failed events. Fires when the platform reports a new delivery state for an outgoing message.
Platform support:
- message.delivered: WhatsApp, Facebook Messenger, SMS, RCS.
- message.read: WhatsApp, Facebook Messenger, Instagram, RCS. Not SMS (carriers report delivery, never read).
- message.played: WhatsApp only, voice messages.
- message.failed: WhatsApp, SMS and RCS (other platforms don't expose
per-message failure via webhook). On SMS,
error.codeis the carrier's numeric code anderror.messageits reason.
Response Body
Example Requests
Shared payload for message.delivered, message.read, message.played and message.failed events. Fires when the platform reports a new delivery state for an outgoing message.
Platform support:
- message.delivered: WhatsApp, Facebook Messenger, SMS, RCS.
- message.read: WhatsApp, Facebook Messenger, Instagram, RCS. Not SMS (carriers report delivery, never read).
- message.played: WhatsApp only, voice messages.
- message.failed: WhatsApp, SMS and RCS (other platforms don't expose
per-message failure via webhook). On SMS,
error.codeis the carrier's numeric code anderror.messageits reason.
/message.readmessage.failed
An outgoing message failed to deliver on WhatsApp or SMS. error carries code, title and message from the platform, for example 131026 for a WhatsApp recipient that is not reachable; on SMS it carries the carrier's error code.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Shared payload for message.delivered, message.read, message.played and message.failed events. Fires when the platform reports a new delivery state for an outgoing message.
Platform support:
- message.delivered: WhatsApp, Facebook Messenger, SMS, RCS.
- message.read: WhatsApp, Facebook Messenger, Instagram, RCS. Not SMS (carriers report delivery, never read).
- message.played: WhatsApp only, voice messages.
- message.failed: WhatsApp, SMS and RCS (other platforms don't expose
per-message failure via webhook). On SMS,
error.codeis the carrier's numeric code anderror.messageits reason.
Response Body
Example Requests
Shared payload for message.delivered, message.read, message.played and message.failed events. Fires when the platform reports a new delivery state for an outgoing message.
Platform support:
- message.delivered: WhatsApp, Facebook Messenger, SMS, RCS.
- message.read: WhatsApp, Facebook Messenger, Instagram, RCS. Not SMS (carriers report delivery, never read).
- message.played: WhatsApp only, voice messages.
- message.failed: WhatsApp, SMS and RCS (other platforms don't expose
per-message failure via webhook). On SMS,
error.codeis the carrier's numeric code anderror.messageits reason.
/message.failedreaction.received
A participant added or removed an emoji reaction on a message, on Instagram, Facebook, WhatsApp, Telegram, Slack or TikTok. On TikTok a like or emoji reaction on a DM arrives only as this event, never as an empty message.received, with reaction.platformMessageId set to the TikTok id of the liked message. On Telegram the bot must be an administrator in the chat; reactions in private chats are never delivered to bots.
Instagram and Facebook accounts connected before August 2026 do not receive this event until their webhook subscription is refreshed. Meta only applies the reactions field when an account is connected and does not backfill it. Sending a reaction is unaffected. If an account sends reactions but never receives them, reconnect it; for a Facebook Page, Re-subscribe a Page to webhooks re-sends the full field set without a reconnect.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for reaction received events (WhatsApp, Telegram, Slack, Instagram, Facebook Messenger, TikTok)
Response Body
Example Requests
Webhook payload for reaction received events (WhatsApp, Telegram, Slack, Instagram, Facebook Messenger, TikTok)
/reaction.receivedreferral.received
Someone opened an existing Instagram or Facebook Messenger conversation through an ig.me or m.me ref link or a returning Messenger ad click. The payload forwards Meta's referral object verbatim: ref and source for links, ad_id and ads_context_data for ad clicks. A referral that rides an inbound message arrives on message.received under metadata.referral instead.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for referral received events (Instagram, Facebook Messenger)
Response Body
Example Requests
Webhook payload for referral received events (Instagram, Facebook Messenger)
/referral.receivedcomment.received
A new comment arrived on a tracked post. On Instagram, comment.isLive: true marks a comment made during a live broadcast; the key is absent on every other comment.
comment.ad is present when the comment was made on paid content: on Instagram it carries ad.id and ad.title from the Meta webhook, on Facebook ad.promotionStatus ("active" for boosted organic posts, "ineligible" for dark post creatives). It is absent for comments on organic posts that are not currently promoted, so if (comment.ad) filters ad-driven comments.
Instagram comments may carry comment.author.instagramProfile (isFollower, isFollowing, followerCount, isVerified). Meta reveals the follow relationship only for people who have messaged the account, and commenting does not grant that consent, so the object is absent for most first-time commenters. An absent object means unknown, never "not a follower". To resolve it on demand, call Instagram follow status; to gate an auto-DM on it, use a comment automation's audience rules.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for comment received events (Instagram, Facebook, Threads, YouTube, LinkedIn, Bluesky, Reddit, TikTok). X/Twitter does NOT fire this event. TikTok events carry only the author id: the comment.update webhook has no username, picture or owner flag.
Response Body
Example Requests
Webhook payload for comment received events (Instagram, Facebook, Threads, YouTube, LinkedIn, Bluesky, Reddit, TikTok). X/Twitter does NOT fire this event. TikTok events carry only the author id: the comment.update webhook has no username, picture or owner flag.
/comment.receivedreview.new
A new review was posted on a connected Google Business Profile account, in real time through Pub/Sub.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for the review.new event (new review posted on a connected account).
Response Body
Example Requests
Webhook payload for the review.new event (new review posted on a connected account).
/review.newreview.updated
A review changed: the reviewer edited their text or rating, or a reply was added through the API or the Google Business Profile dashboard. The payload has the same shape as review.new; when a reply is present, review.hasReply is true and review.reply is populated.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Webhook payload for the review.updated event. Fired when the reviewer edits their text or rating, or when a reply is posted through POST /v1/inbox/reviews/{reviewId}/reply. A reply written directly in Google's own interface does NOT fire this event: Google emits no notification when a reviewReply is written. Same shape as review.new. When a reply is present, review.hasReply is true and review.reply is populated.
Response Body
Example Requests
Webhook payload for the review.updated event. Fired when the reviewer edits their text or rating, or when a reply is posted through POST /v1/inbox/reviews/{reviewId}/reply. A reply written directly in Google's own interface does NOT fire this event: Google emits no notification when a reviewReply is written. Same shape as review.new. When a reply is present, review.hasReply is true and review.reply is populated.
/review.updatedRelated
- Webhooks: create an endpoint, retries, signatures.
- Send a message: reply to
message.receivedwithaccountIdandmessage. - List inbox conversations: the same conversations on demand.
- Comment automations: DM people who comment a keyword.
- Automation webhooks: contact, sequence and workflow run events.
- Chat SDK: a bot framework that consumes these events.
Post webhooks
Receive an event at every step of a post's publishing lifecycle, per platform, and for posts authored natively on the platform.
Automation webhooks
Receive an event when a contact's tags or custom fields change, a contact enters or leaves a sequence, or a workflow run starts, ends or fails.