Skip to content
Schedule Social Media

Press Esc to close.

Instagram webhooks: setup for Instagram, Pages and Threads

Instagram webhooks from Meta's sample code: the hub.challenge handshake, X-Hub-Signature-256 checks, subscribed_apps calls and the fields for Pages and Threads.

Instagram webhooks are HTTPS calls Meta makes to your server when something changes on an account your app serves, such as a new comment, a mention or a message. Facebook Pages and Threads use the same mechanism: one endpoint answers a verification GET, checks the signature on each POST, and your app subscribes each account to the fields it wants.

Every fact on this page comes from Meta's official GitHub repositories (the Graph API webhooks samples, the Messenger and Instagram Postman collections, the Messenger webhooks sample and Meta's Python Business SDK) or from our changelog. No Meta website was read. Where those sources stop, or disagree, the page says so. For the other Meta APIs, start at Meta API use cases.

What this means for you

Webhooks matter to any tool that reacts to activity: a shared inbox, a comment moderation queue, a scheduler that confirms a post went live. Without them, your app has to poll. Meta's Instagram collection says there are two ways to get comments on published media, an API query or a webhook, and that it "strongly recommend[s] using webhooks to prevent rate limiting". Meta Graph API rate limits explains what polling costs.

If you use a scheduler and don't write code, you don't need to do anything. If you build or pay for an integration, the setup below is what brings comments and messages in.

The details: how Instagram webhooks work

One endpoint, three products

Meta's webhooks sample runs a single Express server with three callback paths: /facebook, /instagram and /threads. All three answer the same verification request. The README sets the Threads path up "as a sub use case under the Threads API main use case". So you can run one receiver for all three, as long as you can tell the payloads apart. The object field does that: Meta's samples check for page on Page and Messenger notifications and instagram on Instagram ones.

Step 1: answer the verification request

When you save a callback URL in the App Dashboard, Meta sends a GET to it. The Messenger collection shows the shape:

GET https://your-domain.example/webhooks?hub.mode=subscribe&hub.verify_token=mytoken&hub.challenge=1158201444
ParameterWhat Meta's collection says
hub.modeAlways subscribe
hub.verify_tokenThe string you typed in the Verify Token field in the App Dashboard
hub.challengeA value you must send back

Your endpoint checks that hub.verify_token matches your string and responds with the hub.challenge value. On a mismatch, Meta's current samples return 403; the older Heroku sample returns 400. The collection adds one trap: PHP turns the periods in these parameter names into underscores, so read hub_mode there.

Step 2: check X-Hub-Signature-256 on every POST

Meta's Messenger collection says Meta signs every event notification with a SHA256 signature, keyed with your app's App Secret, and puts it in the X-Hub-Signature-256 header after the prefix sha256=. You don't have to validate it, the collection says, "but you should and we strongly recommend that you do."

This is the check in Meta's newest webhooks sample, written in Python with Flask (one log line left out):

signature_header = request.headers.get("X-Hub-Signature-256")
if not signature_header:
    return "MISSING SIGNATURE HEADER", 403
parts = signature_header.split("=", 1)
if len(parts) != 2:
    return "MALFORMED SIGNATURE HEADER", 403
signature = parts[1]
payload = request.get_data()
expected_signature = hmac.new(
    APP_SECRET.encode("utf-8"), payload, hashlib.sha256
).hexdigest()

if not hmac.compare_digest(signature, expected_signature):
    return "INVALID SIGNATURE HASH", 403

Source: fbsamples/messenger-platform-samples, messenger-api/messenger-api-and-webhooks/app.py, lines 36 to 50, commit 3c3853a.

Two details in the sample matter:

  • Hash the raw body. The sample reads request.get_data() before it parses any JSON. The collection explains why: Meta computes the signature over an escaped unicode version of the payload with lowercase hex digits, so hashing re-encoded or decoded text gives a different result. Its example is äöå, which Meta escapes to äöå.
  • Compare in constant time. The sample uses hmac.compare_digest, not ==.

Step 3: subscribe the app, then each account

Meta's Instagram collection lists two steps to receive notifications. First, subscribe your app to webhook fields in the Meta App Dashboard. Second, enable subscriptions for each app user's Instagram professional account with an API call. The collection says your app "must enable subscriptions" with that call, so dashboard fields alone don't start notifications for an account.

Instagram with Instagram Login. Send a POST to the account's subscribed_apps edge on graph.instagram.com with the fields you want. This is the example request in Meta's collection:

curl -i -X POST \
  "https://graph.instagram.com/v24.0/1755847768034402/subscribed_apps?subscribed_fields=comments,messages&access_token=EAAFB..."

On success the response is {"success": true}. A GET on the same edge returns the subscribed fields, and a DELETE removes them. The collection warns that the delete "will stop webhook notifications to your App" for that account. Replace the v24.0 in Meta's example with a current version from Meta Graph API versions.

Facebook Pages, and Instagram through Facebook Login. Subscribe the Page instead, with a POST to https://graph.facebook.com/{page-id}/subscribed_apps and a Page access token. For Messenger webhooks, the collection asks for a Page access token from someone who can perform the MODERATE task on the Page, plus the pages_messaging and pages_manage_metadata permissions. Meta's Instagram messaging sample, which uses Facebook Login, subscribes its Page to the feed field this way and then receives Instagram messages with object set to instagram. Meta access tokens covers how to get a Page token, and Instagram Login or Facebook Login covers which path to use.

App level, by API. The Messenger collection says the App Dashboard step can also be done with the /app/subscriptions endpoint. Meta's Python Business SDK lists its parameters: object, callback_url, fields, verify_token, include_values and include_client_certificate. The SDK doesn't describe what each one does.

Instagram webhook fields

Meta's Instagram collection subscribes an account to eleven fields:

  • comments and live_comments
  • mentions
  • messages, messaging_postbacks, messaging_seen, messaging_handover, messaging_referral, message_reactions, standby
  • story_insights

mentions is its own field. Meta's Python SDK accepts a longer list on the same edge for Instagram Login (23 values), adding fields such as follow, message_edit, messaging_optins, share_to_story, story_poll_response and story_reactions. The SDK lists names only, so check the dashboard before you rely on one the collection doesn't show.

A comment notification, per the collection, has object set to instagram and an entry with the account ID, a time, field set to comments (or live_comments) and a value holding the comment ID, the commenter's username, the text, and the media's ID and media_product_type. Comments an account makes on its own post also fire a comments webhook, with self_ig_scoped_id set to the account's own ID, so filter those if you auto-reply. The collection also notes that payload syntax varies slightly with the login type your app uses.

Facebook Page webhooks

Meta's Python SDK lists more than 100 fields a Page can subscribe to, including feed, mention, ratings, live_videos, videos and leadgen, plus the Messenger fields. For Page posts, the field to know is feed. Meta's Hubot sample treats a change with verb set to add and item set to status as a new Page post and reads its post_id. The newer Python sample reads entry[].changes[].field and acts only when it equals feed.

The Messenger collection lists the messaging fields with notes on which work for Instagram. For example, message_echoes and message_reads are Messenger only; Instagram uses messages (which includes echoes) and messaging_seen. In the dashboard, Instagram messaging webhooks can be set under Instagram settings.

Our changelog tracks webhook changes as Meta ships them: the Page Integrity webhook added on January 30, 2026, and the Certificate Transparency webhooks removed with v24.0.

Threads webhooks

Meta launched Threads webhooks on August 13, 2024 and later added mention (July 15, 2025), delete (August 1, 2025) and publish (August 15, 2025) webhooks. Meta's webhooks sample adds the Threads Webhooks product as a sub use case under the Threads API use case and points it at the /threads callback path. The handshake is the same hub.mode, hub.verify_token and hub.challenge check.

That's where Meta's GitHub sources stop. Neither the Threads sample app nor the Threads Postman collection contains webhook code, so they don't give the Threads field names, the payload shape or the permission each topic needs. Read those on the Threads webhooks screen in the App Dashboard. Threads API publishing covers the rest of the Threads setup.

Standard Access or Advanced Access

The Messenger collection sets the rule for Messenger and Instagram webhooks. Standard Access is enough to receive notifications from people who have a role on your app, such as admins, developers and testers. Notifications from customers, people with no role on your app, need Advanced Access. So a webhook that works for your testers can stay silent for customers until the app has Advanced Access. Meta App Review: the minimum rules to go live covers how to get Advanced Access.

Respond fast and expect retries

From the Messenger collection:

  • Respond to every notification with 200 OK within 5 seconds or less.
  • Use HTTPS with a valid TLS certificate. Self-signed certificates aren't supported.
  • If a delivery fails, Meta retries "a few more times" right away, so deduplicate.
  • After 15 minutes of failures, Meta alerts your developer account. After 1 hour, you get a Webhooks Disabled alert and your app is unsubscribed from that Page or Instagram account. Subscribe again once it's fixed.
  • Notifications can arrive out of order. Sort by the timestamp field.
  • You can't query past notifications later, so store what you need.

If your server checks Meta's client certificate (mTLS), note that the certificate moved to a Meta-owned CA on March 31, 2026. The common name stays client.webhooks.fbclientcerts.com, and receivers must trust the new CA file or delivery stops.

Test before you subscribe

The Messenger collection gives two local tests. For the handshake:

curl -X GET "localhost:1337/webhook?hub.verify_token=YOUR-VERIFY-TOKEN&hub.challenge=CHALLENGE_ACCEPTED&hub.mode=subscribe"

It should print CHALLENGE_ACCEPTED. The collection's second test posts a JSON body to the same path. It carries no signature, so the check in step 2 rejects it, as it should in production.

Where Meta's samples disagree

Meta's own GitHub code isn't consistent, so don't copy the first sample you find:

  • Signature header: the Messenger collection and the newest Python sample use SHA256 and X-Hub-Signature-256. The Graph API webhooks sample (last changed February 2025), the Instagram messaging sample and the older Messenger Node.js sample still check SHA-1 and X-Hub-Signature. Meta's GitHub sources don't say whether the SHA-1 header is still sent.
  • Which POSTs get checked: the Graph API webhooks sample validates the signature only on /facebook. Its /instagram and /threads handlers accept any POST. Check all three.
  • Old Instagram links: that sample's README still calls Instagram's side the "Subscriptions API" and links to instagram.com client registration. Current Instagram code uses subscribed_apps, as shown above.

What to do next

  • Business owners: Nothing to do. If your tool stops showing new comments or messages, ask the vendor whether its webhooks were disabled.
  • Marketers and agencies: When a client's comments stop arriving in your inbox tool, ask the vendor whether the account's webhook subscription is still active. Meta unsubscribes an app after an hour of failed deliveries.
  • Developers: Serve one HTTPS endpoint, answer hub.challenge, verify X-Hub-Signature-256 over the raw body, return 200 within 5 seconds, deduplicate, and call subscribed_apps for every account you onboard. Plan for Advanced Access before real users.

Questions people ask

What are Instagram API subscriptions?

They are how an app turns on Instagram webhooks for one account. Meta's Instagram Postman collection sends a POST to /{ig-user-id}/subscribed_apps on graph.instagram.com with a subscribed_fields list such as comments,messages. A GET on the same edge lists the fields you're subscribed to, and a DELETE stops notifications for that account.

Why am I not getting Instagram comment webhooks?

Check three things from Meta's samples. The app must be subscribed to the comments field in the App Dashboard, the account must be subscribed through subscribed_apps, and notifications from people without a role on your app need Advanced Access. Meta's GitHub sources don't state any other condition, such as account privacy or app mode, so this page doesn't list one.

Should I check X-Hub-Signature or X-Hub-Signature-256?

Check X-Hub-Signature-256. Meta's Messenger collection says Meta signs every event notification with SHA256, puts it in that header after sha256=, and keys it with your App Secret. Some older Meta samples still check the SHA-1 X-Hub-Signature header; the newest Python sample, updated in October 2026, uses the SHA256 one.

Does Threads have webhooks?

Yes. Meta added Threads webhooks on August 13, 2024, and later added mention, delete and publish webhooks. Meta's webhooks sample sets them up as a sub use case under the main Threads API use case, with the same verification request as Facebook and Instagram. Meta's GitHub sources don't list the Threads field names.

How fast must a webhook endpoint answer Meta?

Meta's Messenger collection says to respond to every notification with 200 OK within 5 seconds or less. Failed deliveries are retried, so deduplicate. If delivery keeps failing for 1 hour, Meta disables the webhooks and unsubscribes your app from that Page or Instagram account, and you have to subscribe again.

Sources

Related

Get an email when a platform changes its API

One email per new entry: what changed, who is affected, and the deadline.

Follow with RSS, or per platform, for example X or Meta.