Meta DM (Facebook & Instagram)
Receive Facebook Messenger and Instagram direct messages, plus comments, as webhook events; reply, react, or show typing through the Send API. This page covers only what is specific to Meta DM: the shared envelope and signature verification live on Receiving Webhooks, the full field reference on Webhook Events, and API keys on Authentication.
Add-on · $29/month · Requires Creator+ planOverview
Facebook Messenger and Instagram DMs share one transport (Meta's Messenger Platform) and one source.channel value: meta_dm. They are the default channel: subscribe to message.received and events begin flowing the moment a page is connected, with no further configuration.
Inbound event types
-
message.received
A customer sends a DM on Facebook or Instagram.
-
message.reel_shared · message.post_shared
A customer shares a reel or a regular post into a DM thread. Same envelope as message.received; the shared media arrives in message.attachments.
-
comment.received
A customer comments on one of your posts or reels, independent of comment triggers. See Comment payload.
Supported send actions
-
send_message · react · unreact · typing_on
Meta DM supports all four Send API actions, and it is the only channel that supports react and unreact.
Requirements: a connected Facebook Page and/or Instagram professional account (Settings → Connections) and the Webhook & Send API add-on active. No extra tier beyond Creator+ is required.
"source": {
"platform": "instagram", // or "facebook"
"channel": "meta_dm"
}
Inbound payload
A DM event uses the standard envelope (field reference). source.platform tells you which surface the message came from; everything else reads the same on both.
Meta-specific fields
-
source.platformstring
facebook or instagram.
-
customer.platform_user_idstring
The platform-assigned user ID (PSID). Pass this as platform_user_id to the Send API. Always present.
-
customer.platform_user_namestring|null
Display name. Present in full profile only.
-
customer.platform_user_usernamestring|null
Instagram @handle (no @). null for Facebook. Present in full profile only.
-
message.idstring
Platform message ID. Use as target_message_id when adding a reaction.
-
message.attachmentsarray
Media the customer sent. See attachment fields. Reel and post shares arrive as message.reel_shared / message.post_shared with the same envelope.
{
"event_id": "a3f8e1c2d4b567890abcdef012345678",
"event_type": "message.received",
"occurred_at": "2026-02-20T08:15:00Z",
"source": {
"platform": "instagram",
"channel": "meta_dm"
},
"conversation": {
"id": 10482
},
"customer": {
"platform_user_id": "17841400123456789",
"platform_user_name": "Jane Doe",
"platform_user_username": "janedoe"
},
"message": {
"id": "mid.1234567890abcdef",
"text_raw": "Hi, do you have availability next Tuesday?",
"attachments": []
},
"meta": {
"version": "v1",
"payload_profile": "full",
"generated_at": "2026-02-20T08:15:00Z"
}
}
Comment payload
A comment.received event fires for every comment on your Instagram or Facebook posts and reels; you don't need a ChatGenius comment trigger configured. It replaces the message object with a source_post object (the post the comment was left on) and a comment object. Use source_post.id as the stable attribution join key.
When the comment also matched one of your comment triggers, comment.trigger_id, comment.trigger_name, comment.matched_keyword, and source_post.url are populated; otherwise those fields are null.
Fields
-
conversation.idinteger|null
Always null for comments (no conversation yet). The follow-up DM arrives as a separate message.received event with a populated id.
-
source_post.idstring
ID of the post/reel the comment was left on. Always present; the attribution join key.
-
source_post.urlstring|null
Permalink. Populated only when the comment matched a trigger targeting a specific post; null otherwise.
-
comment.idstring
Platform comment ID.
-
comment.matched_keywordstring|null
The trigger keyword matched, or null when no trigger matched.
-
comment.trigger_id · comment.trigger_nameinteger / string | null
The matched comment trigger, or null.
-
comment.source_typestring
comment, story, live, or both: the surface the trigger fired on.
{
"event_id": "b7c2e1a4f9d063518adef0129876dcba",
"event_type": "comment.received",
"occurred_at": "2026-02-20T08:15:00Z",
"source": {
"platform": "instagram",
"channel": "meta_dm"
},
"conversation": {
"id": null
},
"customer": {
"platform_user_id": "17841400123456789",
"platform_user_name": null,
"platform_user_username": "janedoe"
},
"source_post": {
"id": "17912345678901234",
"url": "https://www.instagram.com/p/CtExAmple/"
},
"comment": {
"id": "17987654321098765",
"text_raw": "PRICE",
"matched_keyword": "price",
"trigger_id": 42,
"trigger_name": "Pricing DM",
"source_type": "comment"
},
"meta": {
"version": "v1",
"payload_profile": "full",
"generated_at": "2026-02-20T08:15:00Z"
}
}
Sending on Meta DM
Route by conversation_id, or by platform (facebook / instagram) plus platform_user_id (the customer's PSID). Request bodies, idempotency, response format, and errors are on the Send API reference: send_message, react, unreact, typing_on.
Channel limits
-
instagram1,000 chars
-
facebook2,000 chars
Examples on this page use the Send API. New integrations should prefer POST /v1/messages, which accepts the same body and returns the v1 envelope.
POST https://sumgenius.ai/api/meta/webhook-send.php
curl -X POST https://sumgenius.ai/api/meta/webhook-send.php \
-H "X-SumGenius-Api-Key: sgwh_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "confirm-appt-10482-001",
"conversation_id": 10482,
"message_text": "Your appointment is confirmed for Tuesday at 2pm."
}'
The messaging window
Meta restricts when a business can message a customer. This is a platform rule, enforced by Meta, not a ChatGenius limit.
-
Standard 24-hour window
After a customer's last message, you have 24 hours to reply freely.
-
7-day human-agent extension
When a human agent needs more time, Meta's human-agent tag extends the window to 7 days. ChatGenius applies this tag automatically when appropriate, so agent replies within 7 days go through without extra work on your side.
-
Outside the window
A send is rejected as a permanent failure and is not retried. If you subscribe to message.send_failed you receive an event so your system can reconcile.
Reactions and typing indicators are Meta-only capabilities; no other channel supports them. Typing indicators skip the window check, since Meta allows sender_action outside the window.
// one of:
{
"success": false,
"status": "error",
"error": "Meta 7-day window expired."
}
{
"success": false,
"status": "error",
"error": "Cannot send: customer has not initiated a valid messaging window."
}