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
| Parameter | What Meta's collection says |
|---|---|
hub.mode | Always subscribe |
hub.verify_token | The string you typed in the Verify Token field in the App Dashboard |
hub.challenge | A 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:
commentsandlive_commentsmentionsmessages,messaging_postbacks,messaging_seen,messaging_handover,messaging_referral,message_reactions,standbystory_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 OKwithin 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
timestampfield. - 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 andX-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/instagramand/threadshandlers accept anyPOST. 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, verifyX-Hub-Signature-256over the raw body, return 200 within 5 seconds, deduplicate, and callsubscribed_appsfor 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
- Meta on GitHub: Graph API webhooks sample server, heroku/index.js (fbsamples/graph-api-webhooks-samples)
- Meta on GitHub: Graph API webhooks sample README, Threads setup (fbsamples/graph-api-webhooks-samples)
- Meta on GitHub: Graph API webhooks Hubot sample, Page post payload (fbsamples/graph-api-webhooks-samples)
- Meta on GitHub: Messenger Platform API Postman collection, Webhooks guide (fbsamples/messenger-platform-samples)
- Meta on GitHub: Instagram Platform API Postman collection, Webhooks folder (fbsamples/messenger-platform-samples)
- Meta on GitHub: Messenger API and webhooks sample, app.py (fbsamples/messenger-platform-samples)
- Meta on GitHub: Original Coast Clothing Instagram messaging sample, app.js (fbsamples/original-coast-clothing-ig)
- Meta on GitHub: Python Business SDK, Instagram user for Instagram Login (facebook/facebook-python-business-sdk)
- Meta on GitHub: Python Business SDK, Page object (facebook/facebook-python-business-sdk)
- Meta on GitHub: Python Business SDK, Application object, app subscriptions (facebook/facebook-python-business-sdk)
- schedulesocialmedia.com: Graph API v25.0 released, webhook mTLS certificates move to a Meta CA
- schedulesocialmedia.com: Threads webhooks launched
Related
- API
LinkedIn Posts API: what you can schedule and how
LinkedIn's Posts API publishes text, images, video, documents, polls and multi-image posts but has no schedule field. How tools schedule, permissions, limits.
- Tools
Open-source social media schedulers you can self-host
Four open-source schedulers you can run yourself: Postiz, TryPost, Mixpost Lite and SkyScheduler. Licences, networks, what self-hosting takes, hosted prices.
- Tools
Free social media schedulers: all 39 free plans, verified
The best free social media scheduler for most people is Zoho Social (6 accounts) or Buffer (any 3 of 11 networks). All 39 free plans compared, with check dates.
- API
Instagram Content Publishing API: posts, reels, carousels
How the Instagram Content Publishing API works on both logins: containers, reels, carousels of up to 10, stories, and why Meta gives 100, 50 or 25 posts a day.