---
title: "Meta DM (Facebook & Instagram)"
source: https://sumgenius.ai/docs/webhook-meta
generated: 2026-08-25
---

# 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](https://sumgenius.ai/docs/send-api). This page covers only what is specific to Meta DM: the shared envelope and signature verification live on [Receiving Webhooks](https://sumgenius.ai/docs/receiving-webhooks#verify), the full field reference on [Webhook Events](https://sumgenius.ai/docs/webhook-events#envelope), and API keys on [Authentication](https://sumgenius.ai/docs/api-authentication).

Add-on · $29/month · Requires Creator+ plan

### Overview

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](#comment-payload).

Supported send actions

- send_message · react · unreact · typing_on Meta DM supports all four [Send API](https://sumgenius.ai/docs/send-api) actions, and it is the only channel that supports [react](https://sumgenius.ai/docs/send-api#react) and [unreact](https://sumgenius.ai/docs/send-api#unreact).

> **Note**
>
> **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 block on every Meta DM event**

```
"source": {
  "platform": "instagram",  // or "facebook"
  "channel":  "meta_dm"
}
```

### Inbound payload

A DM event uses the standard envelope ([field reference](https://sumgenius.ai/docs/webhook-events#envelope)). `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](https://sumgenius.ai/docs/webhook-events#attachments). Reel and post shares arrive as `message.reel_shared` / `message.post_shared` with the same envelope.

**message.received · full profile**

```
{
  "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.

**comment.received · full profile**

```
{
  "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](https://sumgenius.ai/docs/send-api) reference: [send_message](https://sumgenius.ai/docs/send-api#send-message), [react](https://sumgenius.ai/docs/send-api#react), [unreact](https://sumgenius.ai/docs/send-api#unreact), [typing_on](https://sumgenius.ai/docs/send-api#typing-on).

Channel limits

- instagram1,000 chars
- facebook2,000 chars

Examples on this page use the [Send API](https://sumgenius.ai/docs/send-api). New integrations should prefer [`POST /v1/messages`](https://sumgenius.ai/docs/rest-api#send-message), which accepts the same body and returns the v1 envelope.

**Endpoint**

```
POST https://sumgenius.ai/api/meta/webhook-send.php
```

**curl · reply to a DM**

```bash
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](https://sumgenius.ai/docs/webhook-events#send-failed) you receive an event so your system can reconcile.

> **Note**
>
> 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.

**Rejected 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."
}
```
