Skip to main content

Instagram

Instagram messaging connects your business to users via the Instagram Graph API. Orbit handles the OAuth onboarding, page-level permission scopes, and the async webhook fan-in for inbound DMs, story replies, and quick-reply postbacks. A single Orbit account can attach multiple connected Instagram Business or Creator accounts; messages are billed per-conversation per Meta’s pricing tiers.

Send a message

The body requires to, messaging_type, and message.

messaging_type

Mirrors Meta’s Messenger Platform messaging type and controls when a send is allowed:

message

The message object carries the content. Provide either text or an attachment:
Optional top-level fields: tag (required when messaging_type is MESSAGE_TAG), metadata (a string→string map), and scheduled_at (ISO-8601 timestamp). There is no top-level type, text, or from field — the connected Instagram account is resolved from your API key.

Generic templates

Instagram’s only structured outbound payload is the generic template — a horizontally scrollable carousel of cards, each with an image, title, subtitle, and buttons. Button and receipt templates are Messenger-only and are not supported on Instagram. Because metadata is a string→string map, a generic template is requested through two metadata keys rather than a dedicated message shape:
If elements is missing or is not valid JSON, the send falls back to the plain message.text body.

Response

Capabilities

  • Text + media — text, image, video, audio, file attachments (up to Meta’s per-type size caps).
  • Quick-reply postbacks (inbound) — when a user taps a quick-reply button you presented to them, the tap is delivered as a message.received webhook event with quick_reply.payload populated. Attaching quick-reply buttons to an outbound DM is not currently supported by the send API.
  • Generic templates — multi-card carousels with image, title, subtitle, and buttons. Triggered on a send via metadata fields — see Generic templates below.
  • 24-hour messaging window — inside the standard messaging window, replies are free; outside the window, only MESSAGE_TAGS (HUMAN_AGENT, ACCOUNT_UPDATE, POST_PURCHASE_UPDATE, CONFIRMED_EVENT_UPDATE) can be used.
  • Story mention + story reply — delivered as standard message.received webhook events. A story mention carries metadata.story_mention.url; a story reply carries metadata.story_reply (url and/or id). There are no dedicated instagram.story.* event types — subscribe to message.received and branch on the metadata fields.
  • Inbound webhooks — DMs and postbacks are POSTed to your registered webhook endpoint. Because Instagram messaging runs on Meta’s platform, these callbacks are signed with Meta’s X-Hub-Signature-256 header (the same scheme as WhatsApp), not the Standard Webhooks / Svix scheme Orbit uses for its own outbound webhooks. The header value is sha256=<hex>, where <hex> is HMAC-SHA256(rawBody) keyed with your Meta app secret. Verify it by recomputing the HMAC over the raw request body and comparing with a timing-safe check; requests with a missing or invalid signature are rejected with 401 INVALID_SIGNATURE.

Rate limits

Meta enforces a 200 DM / hour limit per Instagram account (reduced from 5000 in February 2026). Orbit runs a per-tenant, Redis-backed sliding-window counter ahead of every send so you stay under Meta’s quota and avoid RATE_LIMIT_EXCEEDED (429) responses and account restrictions. When a send would exceed the window it is rejected with RATE_LIMIT_EXCEEDED before it ever reaches Meta. The hourly ceiling is operator-tunable without a redeploy — set the env var (Secret Manager / cluster env) and restart the pod:

Onboarding flow

  1. From the dashboard, navigate to Channels → Instagram.
  2. Click Connect Instagram and authorise via Meta’s OAuth dialog. The dialog requests instagram_basic, instagram_manage_messages, pages_messaging, and pages_show_list scopes.
  3. Select the Instagram Business / Creator account you want to attach.
  4. Verify the inbound webhook subscription registered automatically; the webhook URL points to https://api.orbit.devotel.io/api/v1/webhooks/inbound/instagram.

Common errors

The error.code you can branch on is one of three values. Meta-side rejections (expired token, outside the messaging window, non-Business account, opted-out recipient) all surface as MESSAGE_SEND_FAILED — Orbit does not re-expose Meta’s raw error string, so inspect details.provider_status for the upstream HTTP status to tell those cases apart.

Pricing

Pay-as-you-go conversation pricing per Meta’s Messaging Tiers. International destinations vary; the dashboard shows the exact rate per destination before send. See the pricing page for public starter rates.