Messenger & Instagram DM
Facebook Messenger and Instagram Direct messaging share Meta's Graph API and connection flow. Both connect through the same Integrations → Meta entry — a single Embedded Signup that grants pages + IG business accounts in one shot.
Connecting
Integrations → Meta → Continue with Facebook opens Meta's hosted login. You:
- Log in to Facebook (admin on the Page + linked IG business account).
- Grant
pages_messaging,pages_show_list,instagram_basic,instagram_manage_messages,pages_manage_metadata. - Pick the Page(s) and IG account(s) you want connected.
We exchange the short-lived token for a never-expiring Page access token via /oauth/access_token?grant_type=fb_exchange_token. That token is stored encrypted per school.
You'll see two rows on the Integrations page after a successful connect: Messenger and Instagram (if the IG account is linked to the Page).
Webhook subscription
The webhook URL is /api/integrations/meta/webhook on your Kinderpedia domain. We auto-subscribe via POST /{page_id}/subscribed_apps with subscribed_fields = ['messages', 'messaging_postbacks', 'message_reads']. For Instagram, the IG business account inherits Page subscription.
Inbound signatures use X-Hub-Signature-256 HMAC against the Kinderpedia-level Meta app secret. Same enforcement as WhatsApp.
24-hour window (and the policy tags)
Meta's 24-hour rule applies to both Messenger and Instagram. Outside the window, you cannot send free-form messages — but unlike WhatsApp, Meta uses "Message Tags" instead of templates. Tags are policy categories (e.g. ACCOUNT_UPDATE, CONFIRMED_EVENT_UPDATE, HUMAN_AGENT) that justify the out-of-window send.
The inbox picker exposes these tags the same way it exposes WhatsApp templates: pick a tag → write the message → send. The send call to Meta includes messaging_type=MESSAGE_TAG&tag=<TAG>.
Misusing tags can get the Page banned from messaging. Use HUMAN_AGENT only for genuine support interactions, CONFIRMED_EVENT_UPDATE only for actual upcoming activities the parent enrolled in.
Page-Scoped IDs (PSIDs) and IGIDs
Meta doesn't expose end-user Facebook IDs to Page apps. Each conversation surface has a per-Page identity:
- Messenger: PSID (Page-Scoped ID) — unique per Page. Same person on a different Page = different PSID.
- Instagram: IGID — the IG user id, scoped to the IG business account.
Threads in the inbox use these identifiers (messenger:<psid> or instagram:<igid>). When a PSID matches a known parent (via prior linking), the thread is keyed to that parent instead — see Linking conversations to leads.
Profile info
When a new conversation starts, we call GET /{psid}?fields=name,profile_pic to populate the thread header. For Instagram, GET /{igid}?fields=username,profile_picture_url. The avatar URLs are cached on chat_conversations.metadata so we don't re-hit Meta on every page load.
Media
Both surfaces support image, video, audio, file. We re-host inbound media to S3 (Meta URLs expire fast — ~5 min for IG, hours for Messenger). Outbound media is uploaded to Meta's /me/message_attachments endpoint to get a reusable attachment_id, then referenced in the send call.
Size caps are Meta-enforced and identical to WhatsApp.
Instagram quirks
A few IG-specific gotchas:
- Stories replies arrive as a regular message with a special "story_reply" attachment. We render the story snapshot as a quoted bubble.
- Reactions come as
message_reactionevents. We render the emoji as a small chip on the original message. - Voice notes are not supported on IG (DM only allows recorded audio playback, not in-DM recording from API).
- IG Group threads (3+ people) are not supported by Meta's API. Only 1:1 DMs reach the webhook.
Messenger quirks
- Sticker messages arrive as
message.attachments[0].type = 'image'with asticker_idfield. We render them as a small bare image. - Quick replies (the suggested-button chips Page apps can send) are supported on send only — pick "Quick replies" mode in the composer.
- Persistent menu is configured at the Page level on Meta, not in Kinderpedia.
Common errors
| Symptom | Likely cause |
|---|---|
| "Page token expired" (shouldn't happen — they're never-expire) | Admin revoked from Page settings. Re-connect. |
| Webhook events missing | IG account not linked to the Page properly on Facebook's side. |
(#10) Application does not have permission | Missing IG Pro account, or IG account not converted to Business/Creator. |
Out-of-window send returns (#100) Tag not supported | Wrong tag for content — Meta inspects and rejects mismatched tags. |
(#551) Person is not available | User blocked the Page, or deleted their FB/IG account. |
Why one connect for two surfaces?
Meta groups Page + linked IG business account under a single OAuth grant. Trying to connect them separately would require two app reviews and two consent flows. We let Meta hand us both surfaces from one signup.