---
description: Reference for verified Facebook Messenger Page ingress from @flue/messenger.
title: Messenger Channel API | Flue
image: https://flueframework.com/docs/og4.jpg
---

# Messenger Channel API

AI-generated, awaiting review [ View as Markdown](https://flueframework.com/docs/api/messenger-channel/index.md) 

Import from `@flue/messenger`.

## `createMessengerChannel()`

```
function createMessengerChannel<E extends Env = Env>(
  options: MessengerChannelOptions<E>,
): MessengerChannel<E>;
```

Creates GET verification and signed POST delivery routes at `/webhook` for one fixed Facebook Page. The channel verifies Meta’s GET handshake and the exact-body `X-Hub-Signature-256` HMAC, confirms each entry targets the configured Page, and forwards the provider-native payload unchanged. It is stateless and does not deduplicate messages or deliveries.

## `MessengerChannelOptions`

```
interface MessengerChannelOptions<E extends Env = Env> {
  appSecret: string;
  verifyToken: string;
  pageId: string;
  bodyLimit?: number;
  webhook(input: MessengerWebhookHandlerInput<E>): MessengerHandlerResult;
}
```

| Field       | Description                                                   |
| ----------- | ------------------------------------------------------------- |
| appSecret   | Meta app secret for exact-body HMAC-SHA256 validation.        |
| verifyToken | User-chosen token for Meta’s GET verification handshake.      |
| pageId      | Required Page id in every accepted entry.                     |
| bodyLimit   | Maximum JSON body in bytes. Default: 1 MiB.                   |
| webhook     | Callback for one verified, potentially batched HTTP delivery. |

## `MessengerChannel`

```
interface MessengerChannel<E extends Env = Env> {
  readonly routes: readonly ChannelRoute<E>[];
  conversationKey(ref: MessengerConversationRef): string;
  parseConversationKey(id: string): MessengerConversationRef;
  conversationRef(event: MessengerMessagingEvent): MessengerConversationRef | undefined;
}
```

A file named `channels/messenger.ts` serves GET and POST requests at`/channels/messenger/webhook` relative to the `flue()` mount.

The channel is stateless. It does not persist or deduplicate messages, deliveries, reads, or retries.

## Handler input

```
interface MessengerWebhookHandlerInput<E extends Env = Env> {
  c: Context<E>;
  payload: MessengerWebhookPayload;
}
```

`payload` is the provider-native Page webhook payload, passed through after exact-body verification and the fixed-Page identity check. One signed POST may batch several entries and several events. Events stay in Meta’s delivered order. The channel does not reshape, filter, or deduplicate them.

## Webhook payload

```
interface MessengerWebhookPayload {
  object: 'page';
  entry: MessengerEntry[];
  [key: string]: unknown;
}

interface MessengerEntry {
  id: string;
  time: number;
  messaging?: MessengerMessagingEvent[];
  standby?: MessengerMessagingEvent[];
  changes?: MessengerChange[];
  [key: string]: unknown;
}
```

Each `entry` corresponds to one Page. `messaging` carries events the Page is the active receiver for; `standby` carries the same item shape while another app owns the conversation (Handover protocol); `changes` carries Page-field change notifications. Field names and nesting match Meta’s documented wire shapes, and every modeled object carries a `[key: string]: unknown` index signature so authenticated but unmodeled fields forward at runtime rather than being discarded.

## Messaging events

```
interface MessengerMessagingEvent {
  sender?: MessengerSender;
  recipient?: MessengerRecipient;
  timestamp?: number;
  message?: MessengerMessage;
  message_edit?: MessengerMessageEdit;
  postback?: MessengerPostback;
  reaction?: MessengerReaction;
  delivery?: MessengerDelivery;
  read?: MessengerRead;
  optin?: MessengerOptin;
  referral?: MessengerReferral;
  [key: string]: unknown;
}
```

The event family is discriminated by **which property is present**, exactly as Meta delivers it — there is no synthetic `type` field. A `message` event has`event.message`, a postback has `event.postback`, a reaction has`event.reaction`, and so on. Unmodeled families still arrive intact through the index signature.

`MessengerSender` and `MessengerRecipient` carry an optional `id` (the page-scoped id, or PSID) and an optional `user_ref` (a pre-PSID reference set by Customer Matching or the checkbox plugin); the Page is identified by its own`id`.

`MessengerMessage` exposes the native `mid`, optional `text`, `attachments[]`(`type`, `payload.url`, `payload.sticker_id`), `quick_reply.payload`,`reply_to.mid`, `referral`, `commands[].name`, and the echo fields `is_echo`,`app_id`, and `metadata`. Field names stay snake\_case and attachment payloads remain provider-native after verification.

`MessengerOptin.notification_messages_token` is a short-lived marketing-message capability. Keep it and complete native payloads out of model context, dispatch input, logs, and durable session data.

## Conversation identity

```
type MessengerParticipantRef =
  | { type: 'page-scoped-id'; id: string }
  | { type: 'user-ref'; id: string };

interface MessengerConversationRef {
  pageId: string;
  participant: MessengerParticipantRef;
}
```

`conversationKey(ref)` serializes a canonical namespaced identifier suitable for a Flue agent-instance id; `parseConversationKey(id)` parses only keys it produced. These are identifiers, not authorization capabilities, and the page-scoped-id and `user_ref` participant types use distinct key forms.

`conversationRef(event)` derives the counterpart participant — the non-Page actor — for one native messaging event, returning the same `MessengerConversationRef`for both inbound deliveries and Page echoes, or `undefined` when the event carries no usable `sender`/`recipient` pair for this Page.

## Handler results

```
type MessengerHandlerResult =
  | undefined
  | JsonValue
  | Response
  | Promise<undefined | JsonValue | Response>;
```

Returning `undefined` produces `EVENT_RECEIVED` with status `200`, the response body Meta’s quick start documents for a webhook. A JSON-compatible value becomes a JSON response. An ordinary Hono or Fetch `Response` passes through unchanged.

## Errors

* `InvalidMessengerConversationKeyError`
* `InvalidMessengerInputError`, with structured `field`

See [Facebook Messenger setup](https://flueframework.com/docs/ecosystem/channels/messenger/) for Page configuration and project-owned Graph API composition.

## Docs Navigation

Current page: [Messenger Channel API](https://flueframework.com/docs/api/messenger-channel/)

### Sections

* [Guide](https://flueframework.com/docs/getting-started/quickstart/)
* [Reference](https://flueframework.com/docs/api/agent-api/)
* [CLI](https://flueframework.com/docs/cli/overview/)
* [SDK](https://flueframework.com/docs/sdk/overview/)
* [Ecosystem](https://flueframework.com/docs/ecosystem/)

### Runtime

* [ Configuration ](https://flueframework.com/docs/reference/configuration/)
* [ Errors Reference ](https://flueframework.com/docs/api/errors-reference/)
* [ Agent API ](https://flueframework.com/docs/api/agent-api/)
* [ Provider API ](https://flueframework.com/docs/api/provider-api/)
* [ Routing API ](https://flueframework.com/docs/api/routing-api/)
* [ GitHub Channel ](https://flueframework.com/docs/api/github-channel/)
* [ Stripe Channel ](https://flueframework.com/docs/api/stripe-channel/)
* [ Notion Channel ](https://flueframework.com/docs/api/notion-channel/)
* [ Resend Channel ](https://flueframework.com/docs/api/resend-channel/)
* [ Shopify Channel ](https://flueframework.com/docs/api/shopify-channel/)
* [ Intercom Channel ](https://flueframework.com/docs/api/intercom-channel/)
* [ Zendesk Channel ](https://flueframework.com/docs/api/zendesk-channel/)
* [ Salesforce Marketing Cloud Channel ](https://flueframework.com/docs/api/salesforce-marketing-cloud-channel/)
* [ Slack Channel ](https://flueframework.com/docs/api/slack-channel/)
* [ Discord Channel ](https://flueframework.com/docs/api/discord-channel/)
* [ Teams Channel ](https://flueframework.com/docs/api/teams-channel/)
* [ Google Chat Channel ](https://flueframework.com/docs/api/google-chat-channel/)
* [ Linear Channel ](https://flueframework.com/docs/api/linear-channel/)
* [ Telegram Channel ](https://flueframework.com/docs/api/telegram-channel/)
* [ WhatsApp Channel ](https://flueframework.com/docs/api/whatsapp-channel/)
* [ Twilio Channel ](https://flueframework.com/docs/api/twilio-channel/)
* [ Messenger Channel ](https://flueframework.com/docs/api/messenger-channel/)
* [ Streaming Protocol ](https://flueframework.com/docs/api/streaming-protocol/)
* [ Events Reference ](https://flueframework.com/docs/api/events-reference/)

### Advanced

* [ Sandbox Adapter API ](https://flueframework.com/docs/api/sandbox-api/)
* [ Data Persistence API ](https://flueframework.com/docs/api/data-persistence-api/)