Webhooks for the inbox
Inbound messages reach you within seconds through your partner webhook. Three event types cover the inbox. Delivery, signing and retries are the same as for every other event; see Webhook setup.
message.received
Section titled “message.received”A new DM from a contact. data carries the conversation as it is after the message, and the message itself.
{ "id": "evt2b4d6f8h1j3l", "type": "message.received", "created_at": "2026-08-25T10:02:18Z", "partner": "acme", "workspace": "ws7k2m9p4q1r8t3", "external_id": "user_123", "data": { "conversation": { "id": "cnv2b4d6f8h1j3l", "workspace": "ws7k2m9p4q1r8t3", "account": "acig4h2k5m7p9r1", "network": "instagram", "kind": "dm", "platform_thread_id": "17847000000000001", "contact": { "id": "5834920000000001", "name": "Dana de Vries", "handle": "dana.dv", "avatar_url": "https://scontent.example/dana.jpg" }, "post_platform_id": null, "comment_id": null, "last_message_at": "2026-08-25T10:02:17Z", "last_message_preview": "Hi, do you have a slot on Friday afternoon?", "unread": 1, "status": "open", "created": "2026-08-25T10:02:17Z" }, "message": { "id": "msg7q9s1u3w5y2a", "conversation": "cnv2b4d6f8h1j3l", "direction": "in", "kind": "text", "text": "Hi, do you have a slot on Friday afternoon?", "media_url": null, "platform_message_id": "m_AbCdEf0123456789", "sent_by": "contact", "status": "sent", "created": "2026-08-25T10:02:17Z" } }}An image, video, audio or file attachment has the matching kind and a media_url. A tapped quick reply is kind: "postback" with the payload in text.
comment.received
Section titled “comment.received”A new comment on a Page post or on Instagram media, or a reply inside an existing comment thread. Same shape, kind: "comment" on the conversation and on the message.
{ "id": "evt3c5e7g9i2k4m", "type": "comment.received", "created_at": "2026-08-25T11:40:03Z", "partner": "acme", "workspace": "ws7k2m9p4q1r8t3", "external_id": "user_123", "data": { "conversation": { "id": "cnv3c5e7g9i2k4m", "workspace": "ws7k2m9p4q1r8t3", "account": "acig4h2k5m7p9r1", "network": "instagram", "kind": "comment", "platform_thread_id": "17990000000000001", "contact": { "id": "5834920000000002", "name": "Sam K.", "handle": "sam.k", "avatar_url": null }, "post_platform_id": "17900000000000001", "comment_id": "17990000000000001", "last_message_at": "2026-08-25T11:40:02Z", "last_message_preview": "How much is a cut?", "unread": 1, "status": "open", "created": "2026-08-25T11:40:02Z" }, "message": { "id": "msg9s1u3w5y7a4c", "conversation": "cnv3c5e7g9i2k4m", "direction": "in", "kind": "comment", "text": "How much is a cut?", "media_url": null, "platform_message_id": "17990000000000001", "sent_by": "contact", "status": "sent", "created": "2026-08-25T11:40:02Z" } }}Match post_platform_id against targets[].platform_post_id on your posts to show comments next to the post they belong to.
message.sent
Section titled “message.sent”Fires for every outbound message, whichever surface sent it: your API call, the widget, the dashboard, an MCP client. Use it to mirror replies sent outside your own code.
{ "id": "evt4d6f8h1j3l5n", "type": "message.sent", "created_at": "2026-08-25T10:05:41Z", "partner": "acme", "workspace": "ws7k2m9p4q1r8t3", "external_id": "user_123", "data": { "conversation": { "id": "cnv2b4d6f8h1j3l", "kind": "dm", "account": "acig4h2k5m7p9r1", "network": "instagram", "last_message_at": "2026-08-25T10:05:40Z", "unread": 1, "status": "open" }, "message": { "id": "msg8r0t2v4x6z3b", "conversation": "cnv2b4d6f8h1j3l", "direction": "out", "kind": "text", "text": "Yes, Friday 15:00 or 16:30 is free. Which one?", "media_url": null, "platform_message_id": "m_XyZ0123456789abc", "sent_by": "embed", "status": "sent", "created": "2026-08-25T10:05:40Z" } }}If you only ever reply through the API, you can ignore message.sent; you already have the message from the POST response.
Keeping your inbox in sync
Section titled “Keeping your inbox in sync”- Upsert the conversation by
data.conversation.idon every event, then append the message bydata.message.id. Both ids are stable. - De-duplicate on
X-MissLess-Delivery. A retried delivery carries the same id. - Order is not guaranteed across events. Sort by
message.created, and takelast_message_atfrom the conversation rather than from the event you happened to receive last. - Mark read on your side by calling
PATCH /v1/conversations/:idwith{ "unread": 0 }when staff opens the thread. The widget does the same, so the count stays consistent between your UI and the embedded inbox. - What you receive can contain personal data: names, handles, message text. Store it under your own legal basis and delete it when you no longer need it. See Data and privacy.