> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Messenger onboarding playbook

> Step-by-step playbook for connecting a Meta Page to Orbit Messenger — OAuth connect, Page selection, webhook subscription, PSIDs, personas, messaging windows, One-Time Notifications, and the error codes you will actually see.

# Messenger Onboarding Playbook

This guide walks you end to end from an empty Messenger channel to a working, monitored setup. It complements the [Messenger channel page](/channels/messenger), which documents the API shapes — this guide is the ordered playbook you follow the first time (and re-run when you attach an nth Page).

The whole path takes minutes: unlike WhatsApp or 10DLC, there is no approval cycle, no registration, and no Orbit-side cost.

## 1. Prerequisites

Before you open the dashboard, confirm:

* **A Meta Business Manager account** at business.facebook.com that you (or your org admin) can access.
* **Ownership of the Facebook Page** you want to attach — you must be a Page admin; Meta's OAuth dialog only lists Pages your Facebook user controls.
* **`pages_messaging` scope approval** — the OAuth dialog asks for `pages_messaging` and `pages_show_list`. If your company policy routes Meta app review through a central team, pre-approve those two scopes or the connect step stalls.

You do not need a Meta developer app, a WABA, or any contracted Meta seats to do any of this. Messenger is \$0 on Orbit's side — see [Pricing](/channels/messenger#pricing).

## 2. Connect a Page (OAuth → selection → webhook subscription)

Do this once per Page. If you manage a brand portfolio, repeat for each Page.

1. In the dashboard, go to **Channels → Messenger**.
2. Click **Connect Page**. Meta's OAuth dialog opens and requests `pages_messaging` and `pages_show_list`.
3. **Select the Page(s)** to attach. Pick them all now if you intend to run several; each selected Page becomes a distinct channel entry on Orbit.
4. Orbit **subscribes the Page to webhook events automatically** — you do not wire callbacks by hand.
5. (Recommended) Send yourself a test message to the Page from a personal Facebook account, then confirm the inbound `message.received` event appears on your webhook endpoint before you go live.

### API equivalent

OAuth is dashboard-only — there is no API endpoint to complete the Meta sign-in — but the send call after Page attach is the same shape every time:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/messages/messenger \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "<recipient_psid>",
    "messaging_type": "RESPONSE",
    "message": { "text": "Hello from the onboarding playbook." }
  }'
```

A `queued` status in the response means Meta accepted the send request; treat `message.delivered` as your real delivery signal (see [What fires a webhook](#7-what-fires-a-webhook)).

## 3. Recipient PSIDs — where the recipient ID comes from

Every Messenger send addresses a recipient by **PSID** (Page-Scoped ID), not a Facebook user id or an email. A PSID is stable per (recipient, Page) pair but differs across Pages.

You receive the PSID:

* **Inbound webhooks.** Every inbound message carries the sender's PSID; store it on the contact so outbound replies reuse it. This is the primary path for conversational use cases.
* **m.me links.** A link of the form `m.me/<page-id>` opens your Page's Messenger thread; when the user messages, the PSID arrives on the inbound webhook — link PSIDs back to the referring campaign by parsing the `ref` parameter.
* **Referral events from ads or plugins.** When a user comes in through a Click-to-Messenger ad or a web plugin, Meta delivers a referral alongside the message; Orbit surfaces the PSID on the inbound event the same way.

Do not treat PSIDs as globally portable — a recipient that messages Page A then Page B shows a different PSID for each. Key your contacts by (PSID, Page) unless you have resolved identity across them in CDP.

## 4. Personas — reply as a named agent on the same Page

If your agents reply individually (e.g. "Sarah, Support") instead of the brand silhouette, configure sender personas from **Settings → Channels → Messenger** after Page attach. Each persona has a name and optional avatar; agents pick a persona when composing from the inbox, and outbound messages carry that persona label to the recipient.

Limits that matter operationally:

* Personas are **per Page** — building them per Page is part of onboarding a Page.
* Personas apply to **PSID-typed recipients only**; they do not change behaviour on SMS/WhatsApp/email.
* The Page itself still owns identity and routing — a persona is a display label, not a separate sender.

Skip personas if you only send template/automation traffic; they exist for conversational inbox use.

## 5. Messaging windows and tags — choose the right `messaging_type`

The [channel page table](/channels/messenger#messaging-windows) lists the four shapes. In practice:

* **`RESPONSE`** (standard 24h window) — the default; any content, inside 24h since the user's last message. Most conversational traffic.
* **`HUMAN_AGENT`** — up to 7 days; use only for human support agents catching up to a backlog, not for scheduled/template sends.
* **`MESSAGE_TAG`** — anytime, but only with one of Meta's approved tags (`CONFIRMED_EVENT_UPDATE`, `POST_PURCHASE_UPDATE`, `ACCOUNT_UPDATE`) and only transactional content. A `MESSAGE_TAG` send without a valid `tag` field is rejected.
* **OTN** — see [One-Time Notifications](#6-one-time-notification-tokens).

Rule of thumb: if you can work inside `RESPONSE`, do; escalate to `HUMAN_AGENT` for real agent replies; use `MESSAGE_TAG` for transactional receipts/updates; use OTN for the single re-engagement follow-up. Meta enforces these and will 422 on misuse.

## 6. One-Time Notification (OTN) tokens

OTN is the escape hatch when none of the windows fit and you need one more message — a re-engagement prompt, a cart-recovery ping, notification opt-in. The trade is deliberate: one token buys exactly one message.

1. **Request the token.** Send an OTN request message to the user (inside an open window) that asks them to opt in to a one-time follow-up. Meta renders the prompt; the user's tap stores a token against their PSID.
2. **Spend the token later.** A subsequent send that references the token can go through even after the 24h window has closed — once. After that the token is consumed.

Design notes:

* Request tokens as soon as the user engages if re-engagement is part of the lifecycle (e.g. cart abandonment in commerce flows) — you cannot request after the window closes.
* The token is per-PSID and single-use; track spend server-side.
* OTN is for a single follow-up, not a campaign batch. For real batch follow-up outside the window, the channel is still governed by `MESSAGE_TAG` or `HUMAN_AGENT`.

## 7. What fires a webhook — and what does not

Design your automation against the actual event surface.

* **Inbound** — `message.received` fires for inbound text and attachment messages (the ones users send in the thread).
* **Outbound lifecycle** — `message.sent` (Meta accepted), `message.delivered` (reached the device), `message.read` (recipient opened the conversation), `message.failed` (Meta-reported delivery failure).
* **Not dispatched** — postbacks (button taps), referrals (m.me links, Click-to-Messenger ads), and Opt-in plugin events are processed by Orbit but **do not fire webhooks**. Do not build automations that expect a `message.received` for them; rely on the routing Orbit does internally.
* **Delivery signal** — treat `message.delivered` as confirmation; `message.sent` only means acceptance by Meta.

When you design flows that must react to a button tap or an ad referral, do the reaction inside Orbit (flow/inbox automation), not in your webhook consumer.

## 8. Common errors — deep dive

The [channel page table](/channels/messenger#common-errors) is the reference. Here is how to fix each in practice.

### `INVALID_RECIPIENT` (422)

The recipient PSID is missing or empty in `to`. Fixes:

* Confirm you captured the PSID from an inbound webhook (or a m.me link flow) before you try to send; a `INVALID_RECIPIENT` on first send almost always means the capture step was skipped.
* Validate the PSID string in your integration before calling the API — empty/whitespace strings reach Meta otherwise.

### `MESSAGING_WINDOW_CLOSED` (422)

You sent a `RESPONSE`/`UPDATE` message (or a `MESSAGE_TAG` without a `tag`) more than 24h after the recipient's last inbound. The response `details` includes `hours_since_last_inbound` and `last_inbound_at` — log both before choosing a recovery path.

Recovery, in escalating cost:

1. Wait for the user to re-engage (cheapest — the window re-opens).
2. Switch to `messaging_type: MESSAGE_TAG` with an approved transactional tag.
3. Switch to `messaging_type: HUMAN_AGENT` if a human is genuinely replying.
4. Consume an OTN token if you hold one.

Do not blindly retry the same call — the window is still closed.

### `MESSAGE_SEND_FAILED` (502)

Meta's Send API rejected the request. Upstream detail is in `details.provider_message`; check it before opening a support ticket.

* **Expired Page access token** — Meta rotates tokens roughly every 60 days. Reconnect from **Channels → Messenger → Reconnect**.
* **Dropped webhook subscription** — re-subscribe from the channel detail page (**Re-subscribe**).
* **Invalid/blocked recipient** — Meta sometimes blocks delivery to a PSID after spam reports or Platform terms actions; treat as a genuine failure and suppress future sends to that PSID.

### `RATE_LIMIT_EXCEEDED` (429)

Per-tenant send rate exceeded. Honour `Retry-After` and, for campaigns, batch through the campaign channel rather than a single-message loop. For sustained throughput, see [Requesting Higher Limits](/guides/rate-limits#requesting-higher-limits).

## Where to go next

* [Messenger channel page](/channels/messenger) — the API reference for channel-specific body shapes.
* [Send and receive messages](/guides/send-receive-messages) — the cross-channel send pattern.
* [Inbox setup](/guides/inbox-setup) — route inbound Messenger traffic to your team.
* [Best practices](/guides/best-practices) — platform-wide sending hygiene.
