The Instagram API in 2026: A Complete Developer Guide

Every Instagram API in 2026: which one you need, the auth paths, working curl for publishing and insights, and the real rate limit formula.

Ronak Shah
Growth at Phyllo
August 11, 2026
August 10, 2026
3D glossy Instagram and Facebook app icons beside a speedometer gauge, representing the Instagram Graph API auth path and its rate limits
Summarize this article with AI
GeminiChatGPTClaudePerplexityGrok

Meta runs three live Instagram APIs in 2026 and shut the Basic Display API down on 4 December 2024. This guide maps every API to a use case, covers both auth paths and their scopes, gives working curl for publishing and insights, explains the real rate limit formula, and lists what Meta will not release at any access tier.

This is some text inside of a div block.
  • Meta runs three live Instagram APIs in 2026 and shut Basic Display down on 4 December 2024.
  • The Graph API publishes through graph.facebook.com while Instagram Login serves professional accounts from graph.instagram.com.
  • The real rate limit is 4,800 multiplied by the account's impressions over a rolling 24 hours, not a flat 200 calls per hour.
  • Publishing a Reel takes three calls because Meta transcodes asynchronously, so you create a container, poll until FINISHED, then publish.
  • Stories publishing is limited to Business accounts, and no compliant route to personal accounts exists.

Meta runs three live Instagram APIs in 2026 and killed a fourth. The Instagram Graph API handles publishing, comments, insights and hashtag search for Business and Creator accounts, authenticated through Facebook Login and served from graph.facebook.com. The Instagram API with Instagram Login covers the same professional accounts through a direct Instagram auth path with no Facebook Page required, and it is served from a different host, graph.instagram.com. The Instagram Messaging API is a subset of the Graph API for direct messages. The Basic Display API was shut down on 4 December 2024 and every endpoint returns an error.

The API costs nothing to call. What it costs you is app review, a Business or Creator account requirement, and a rate limit that is not the flat 200 calls per hour most guides quote. The real formula is 4,800 multiplied by your account's impressions over a rolling 24 hours, which means your ceiling moves with your users' reach.

This guide is the full map. Auth paths and scopes, working curl for every core operation including the three-step Reels publish, the rate limit system explained properly, production patterns for webhooks and token refresh, and an honest list of what Meta will not hand over at any access tier. Everything below is current as of July 2026.

Part 1: What is the Instagram API, and which one do I need?

The Instagram API is Meta's set of HTTP endpoints for reading and writing Instagram data on behalf of a professional account that has authorised your app. Which one you need comes down to one question: do you publish and analyse, or do you only read? Everything else follows from that.

Five names circulate and they map to three live products. Getting the name right decides which documentation applies to you, which host you call, and which scopes you request.

NameStatusHostWhat it doesAuth
Instagram Basic Display APIDead, 4 Dec 2024NoneWas read-only personal account accessGone
Instagram Graph APILivegraph.facebook.comPublishing, comments, mentions, hashtag search, insights, Business DiscoveryFacebook Login
Instagram API with Facebook LoginLivegraph.facebook.comMeta's newer name for the same product aboveFacebook Login
Instagram API with Instagram LoginLivegraph.instagram.comProfessional account access without a linked Facebook Page. Cannot touch ads or taggingInstagram Login
Instagram Messaging APILivegraph.instagram.comSend API, templates, conversations. Subset of the aboveInstagram Login

The host difference is the gotcha that costs people an afternoon. The Facebook Login path calls graph.facebook.com. The Instagram Login path calls graph.instagram.com. Copy a curl from the wrong guide and every request 400s with an error that does not mention hostnames.

The December 2024 shutdown, briefly

Meta announced the Basic Display retirement in September 2024 and switched it off on 4 December 2024. No grace period, no partial support. Tokens stopped refreshing and every integration built on it failed at once.

The reason it hurt more than a normal deprecation is that Basic Display was the only official route to a personal Instagram account, and both replacements require a Professional account. For a class of consumer apps there was nothing to migrate to. Day One, the journaling app, had built Instagram import into a paid tier. TechCrunch reported that the replacement APIs only worked for business accounts and did not cover what Day One needed. The feature was removed rather than rebuilt.

I go through the access tiers, the approval path and the rejection patterns in more depth in our guide to Instagram API access.

Which API should you build on?

What you are buildingWhich APIWhy
Feed embed or gallery widgetInstagram LoginRead access to profile and media, no Facebook Page to configure
Scheduling or publishing toolGraph APIContent publishing, and Stories publishing is Business-account only
Creator analytics dashboardGraph APIInsights endpoints, audience demographics for the authorised account
Comment moderation or community toolEitherBoth paths expose comment management with different scope names
DM automation or support inboxInstagram LoginSend API lives on graph.instagram.com
Competitor or hashtag researchGraph API, with limitsHashtag Search and Business Discovery exist but are capped hard. See Part 6
Anything reading a personal accountNone existsNo compliant path since December 2024

Part 2: How does authentication work?

OAuth 2.0 authorization code flow on both paths, with an important structural difference. The Facebook Login path makes you hop through a Facebook Page to reach the Instagram account. The Instagram Login path talks to the Instagram account directly.

The flow itself is standard. Your app redirects the user to an authorization URL carrying your App ID and requested scopes. The user approves a consent screen. Instagram redirects back with a short-lived authorization code. Your server exchanges that code plus your App Secret for an access token. Never do that exchange client side, because the App Secret must not leave your backend.

Scopes, by path

The two paths use different scope names for the same capabilities, which is another reason copied code fails. Request the minimum set your core feature needs. Over-requesting is one of the most common app review rejections and it is free to avoid.

Facebook Login pathInstagram Login path
instagram_basicinstagram_business_basic
instagram_content_publishinstagram_business_content_publish
instagram_manage_commentsinstagram_business_manage_comments
instagram_manage_insightsNo direct equivalent, insights are narrower
pages_show_list, pages_read_engagementNot required, no Page involved
No messaging equivalentinstagram_business_manage_messages

Token types and lifetimes

TokenLifetimeUse it for
Authorization codeMinutesOne server-side exchange, then discard
Short-lived user tokenAbout 1 hourTesting in the Graph API Explorer
Long-lived user tokenAbout 60 daysProduction user connections. Refreshable after 24 hours
Page access tokenInherits the user tokenActing on behalf of the Page linked to the Instagram account
System user tokenDoes not expireServer-to-server automation you own. Business Manager only

The 60-day expiry is where integrations die quietly. There is no single outage to alert on. Connections fail one at a time as each user reaches their own expiry, and the support tickets arrive before your monitoring does. Refresh at day 50 to 55, and alert on refresh failures rather than on request failures.

An App ID and App Secret are not an access token. The App ID identifies your app and does not expire on a schedule. An access token is tied to one user, expires, and only exists after that user approves your app. Most integrations need both.

Part 3: Working code for every core operation

Everything below is curl against the Facebook Login path unless noted. Swap the host to graph.instagram.com and the scope names per the table above for the Instagram Login path. Replace the version string with the current one, which was v25.0 as of early 2026.

Step 1: find the Page token and the Instagram user ID

On the Facebook Login path you cannot call Instagram endpoints with a plain user token. You first list the Pages the user manages, then pull the Page token and the linked Instagram account ID out of that response.

curl -s -X GET \
  "https://graph.facebook.com/v25.0/me/accounts\
?fields=name,access_token,tasks,instagram_business_account\
&access_token=USER_ACCESS_TOKEN"

# Response
{
  "data": [
    {
      "name": "Your Page",
      "access_token": "PAGE_ACCESS_TOKEN",
      "instagram_business_account": { "id": "IG_USER_ID" },
      "id": "PAGE_ID",
      "tasks": ["ANALYZE","ADVERTISE","MESSAGING","MODERATE",
                "CREATE_CONTENT","MANAGE"]
    }
  ]
}

Keep PAGE_ACCESS_TOKEN and IG_USER_ID. Almost every call below uses one or both. If you already know the Page ID, query it directly and skip the list:

curl -s -X GET \
  "https://graph.facebook.com/v25.0/PAGE_ID\
?fields=name,access_token,instagram_business_account\
&access_token=USER_ACCESS_TOKEN"

Step 2: read the profile and the media list

The Graph API is a node and edge model. Nodes are things: a profile, a photo, a comment. Edges are the relationships between them, so the media edge on a user node returns that user's posts. You request exactly the fields you want and nothing else comes back.

# Profile
curl -s -X GET \
  "https://graph.facebook.com/v25.0/IG_USER_ID\
?fields=id,username,followers_count,media_count\
&access_token=PAGE_ACCESS_TOKEN"

# Media, newest first, 25 per page
curl -s -X GET \
  "https://graph.facebook.com/v25.0/IG_USER_ID/media\
?fields=id,caption,media_type,media_url,permalink,\
like_count,comments_count,timestamp\
&limit=25&access_token=PAGE_ACCESS_TOKEN"

Two behaviours to design around. Ordering is not supported, so you cannot ask the API to sort. And every endpoint uses cursor-based pagination except the User Insights edge, which is the only one that supports time-based pagination. Do not write one pagination helper and assume it covers everything.

Step 3: publish a Reel, the three-step container flow

Publishing is never a single call. You create a container, poll it until Meta finishes transcoding, then publish the container. Teams that miss the polling step ship code that works on small test files and fails on real ones.

3a. Create the container.

curl -s -X POST \
  "https://graph.facebook.com/v25.0/IG_USER_ID/media\
?media_type=REELS\
&video_url=https://cdn.example.com/reel.mp4\
&caption=Hello%20World\
&share_to_feed=false\
&access_token=PAGE_ACCESS_TOKEN"

# Response
{ "id": "18270815569115548" }   # this is IG_CONTAINER_ID

The video_url must be publicly reachable, because Meta pulls the file from your server rather than accepting an upload. share_to_feed set to true puts the Reel in both the Feed and the Reels tab. False keeps it in Reels only.

3b. Poll the container until it is ready.

curl -s -X GET \
  "https://graph.facebook.com/v25.0/IG_CONTAINER_ID\
?fields=status_code,status\
&access_token=PAGE_ACCESS_TOKEN"

# Response while transcoding
{ "status_code": "IN_PROGRESS", "status": "Media is being processed." }

# Response when ready
{ "status_code": "FINISHED",
  "status": "Finished: Media has been uploaded and it is ready to be published.",
  "id": "18270815569115548" }

3c. Publish it.

curl -s -X POST \
  "https://graph.facebook.com/v25.0/IG_USER_ID/media_publish\
?creation_id=IG_CONTAINER_ID\
&access_token=PAGE_ACCESS_TOKEN"

# Response
{ "id": "90011803596441" }   # IG Media ID

Poll on a backoff rather than a tight loop, because every poll consumes quota from the same budget the publish call needs. Treat any status_code other than FINISHED as not ready, and surface ERROR states to the user rather than retrying blindly.

Reels media specifications

Uploads that violate these fail at the container stage with messages that are not always specific. Validate before you call.

PropertyRequirement
Container formatMOV or MP4, MPEG-4 Part 14
Video codecHEVC or H.264
Audio codecAAC, 48 kHz
Frame rate23 to 60 FPS
Picture sizeMaximum 1920 horizontal pixels, 9:16 recommended
Video bitrate25 Mbps maximum
Audio bitrate128 kbps
Duration3 seconds minimum, 15 minutes maximum
File size1 GB maximum

One rule that catches product teams rather than engineers: content publishing is available to all Instagram Professional accounts, except Stories, which are Business accounts only. If your product promises Stories scheduling to Creator accounts, that promise cannot be kept.

Step 4: comments

# Read comments on a post
curl -s -X GET \
  "https://graph.facebook.com/v25.0/MEDIA_ID/comments\
?fields=id,text,username,timestamp,like_count\
&access_token=PAGE_ACCESS_TOKEN"

# Reply to a comment
curl -s -X POST \
  "https://graph.facebook.com/v25.0/COMMENT_ID/replies\
?message=Thanks%20for%20this\
&access_token=PAGE_ACCESS_TOKEN"

# Hide a comment
curl -s -X POST \
  "https://graph.facebook.com/v25.0/COMMENT_ID\
?hide=true&access_token=PAGE_ACCESS_TOKEN"

Do not poll for new comments. Subscribe a webhook instead. Polling every minute across a few hundred accounts will exhaust quota that your publishing depends on, for reasons Part 4 makes concrete.

Step 5: insights

# Account level
curl -s -X GET \
  "https://graph.facebook.com/v25.0/IG_USER_ID/insights\
?metric=reach,impressions,profile_views,follower_count\
&period=day&access_token=PAGE_ACCESS_TOKEN"

# Post level
curl -s -X GET \
  "https://graph.facebook.com/v25.0/MEDIA_ID/insights\
?metric=impressions,reach,saved,engagement\
&access_token=PAGE_ACCESS_TOKEN"

Insights metrics have changed twice in the last eighteen months and Meta deprecates them on short notice. Check the changelog before you assume a field still exists, and design your dashboard to degrade gracefully when a metric returns nothing rather than throwing.

Step 6: send a direct message

Messaging lives on the Instagram Login path and therefore on a different host. Conversations only start when the Instagram user messages your app user first, and you can only reply inside a 24-hour window after their last message.

curl -s -X POST \
  "https://graph.instagram.com/v25.0/IG_USER_ID/messages" \
  -H "Authorization: Bearer IG_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": { "id": "IG_SCOPED_ID" },
    "message": {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "button",
          "text": "What do you want to do next?",
          "buttons": [
            { "type": "web_url",
              "url": "https://example.com",
              "title": "Visit site" }
          ]
        }
      }
    }
  }'

Four messaging constraints worth knowing before you scope a support inbox. Group messaging is not supported, so one conversation means one customer. Your app user must own any media referenced in a message. Messages sitting in the Requests folder with no activity for 30 days stop being returned by the API. And when a customer shares a post, the webhook payload carries only the URL, not the content.

Part 4: The rate limit system, properly explained

Instagram does not run one rate limiter. It runs two, and which applies depends on the endpoint. Almost every guide reports a flat 200 calls per hour, and for the main Instagram Platform endpoints that number is not the mechanism. The real formula, from Meta's own rate limiting documentation, is:

Calls within 24 hours = 4800 × Number of Impressions

Impressions here means the number of times any content from the connected professional account entered a person's screen in the last 24 hours. The count is tracked per app and account pair, in a rolling 24-hour window, and it moves as that account's reach moves.

Work the arithmetic, because it is the whole point. An account with 1,000 impressions yesterday gives you 4,800,000 calls today. An account with 10 impressions gives you 48,000. A widely shared guide currently states that ten impressions yields 48 calls, which is out by a factor of a thousand, and I mention it only because capacity plans get built on numbers like that.

So the honest summary is not that small accounts get a tiny allowance in absolute terms. It is that the ceiling is invisible and it moves. You cannot read the impression count through the API. You only get a percentage in a response header, so you are managing against a limit you cannot see, on an account whose reach changes daily.

Two limiters, and which endpoints use which

LimiterApplies to
Business Use Case, 4800 × impressionsMedia, insights, comments, mentions, content publishing. Effectively the whole Instagram Platform surface
Platform Rate LimitsBusiness Discovery and Hashtag Search. A separate system with separate ceilings
Messaging limitsCounted per professional account and per API. Overlaps with BUC, so a DM consumes both
Publishing capAround 25 API-published feed posts per 24 hours per account, independent of everything above

Two consequences that catch teams. First, all Instagram Platform endpoints for a given app and account pair share one BUC pool, so an aggressive insights poller will quietly eat the budget your publishing needs. Second, Advanced Access does not change the formula. Teams hitting throttling often apply for higher access expecting relief, wait weeks, and get none.

Read the usage header

Every response carries X-Business-Use-Case-Usage. Parse it on every response, not just on failures, and build it into your HTTP client so nobody has to remember.

"X-Business-Use-Case-Usage": {
  "IG_USER_ID": [
    {
      "type": "INSTAGRAM",
      "call_count": 28,        // percent of quota used, not raw calls
      "total_cputime": 10,     // percent
      "total_time": 20,        // percent
      "estimated_time_to_regain_access": 0   // minutes, when throttled
    }
  ]
}

call_count is a percentage, not a raw count. Throttle yourself at 80 rather than waiting for the block. When you are throttled, estimated_time_to_regain_access tells you how long, so use it instead of guessing a backoff interval. Error code 80002 is the one that means quota exhausted.

There are also CPU and time budgets alongside the call budget, calculated as 720,000 multiplied by impressions for total CPU time and 2,880,000 multiplied by impressions for total time. An expensive query can exhaust those before your call count gets close.

A trap worth naming: your development accounts lie to you. Test accounts usually belong to team members with normal Instagram activity, which gives a comfortable quota that your real customers, especially new creators, will not have. We wrote up the specific error patterns in our guide to Instagram API rate limit errors.

Part 5: Production patterns

Four patterns separate an integration that survives a year from one that needs a rewrite. None of them are Instagram-specific, but Instagram punishes their absence harder than most APIs.

Webhooks instead of polling

Meta offers no firehose. If you want near real-time updates on comments, mentions or messages, you subscribe webhooks at the app level and then re-subscribe per user. Polling is the fastest way to burn a BUC budget for no benefit. Configure a public endpoint that accepts POST, subscribe only to the topics you use, and validate the signature on every payload, because an unvalidated webhook endpoint is an open door.

Batch requests

Fetching comment counts for twenty posts as twenty calls is twenty calls against your quota. Batching bundles independent calls into one HTTP request and one response, which cuts round trips and quota consumption together.

A token refresh job, not a token refresh function

# Refresh a long-lived token, Facebook Login path
curl -s -X GET \
  "https://graph.facebook.com/v25.0/oauth/access_token\
?grant_type=fb_exchange_token\
&client_id=APP_ID\
&client_secret=APP_SECRET\
&fb_exchange_token=CURRENT_LONG_LIVED_TOKEN"

# Run this on a schedule at day 50-55, per connected account.
# Alert on refresh failures, not on request failures.
# A token can also die early if the user changes their password
# or revokes the app, so check validity at startup too.

An error taxonomy, not a retry loop

Sort failures into retry and do-not-retry before you write any retry code, because retrying the wrong class of error makes throttling worse rather than better.

ClassExamplesHandling
Retry with backoff429, 80002 quota exhausted, 5xx, network timeoutsExponential backoff with jitter. Use estimated_time_to_regain_access when present
Do not retry, fix firstMissing scope, malformed query, unsupported media, invalid captionSurface the error. The same payload will fail forever
Do not retry, re-authExpired or revoked token, user removed the appPrompt the user to reconnect. Mark the connection dead in your UI
Do not retry, waitContainer not FINISHED, media still transcodingPoll the status endpoint on a backoff

Part 6: What Meta will not give you, at any tier

Six things. Four of them are not difficulty, they are Meta deciding the data belongs to the account holder, which means no access tier and no approval will move them.

What you cannot getWhyClosest available
Audience demographics for a creator who has not authorised your appReleased to the account owner onlyDemographics for creators who connect through your product
Any personal account dataNo endpoint since December 2024Ask the user to convert to Professional
Follower and following listsNot exposed on the Graph APIFollower counts only
Historical Stories metricsStories expire in 24 hours and are not archivedLive polling while the Story is up
Earnings or monetisation dataNever exposed on any Instagram surfaceConsented income signals across platforms
Deep competitive researchHashtag Search and Business Discovery are capped per account per week and return top media onlyA purpose-built listening tool

That last row is the one product managers argue with. Hashtag Search and Business Discovery genuinely exist, and they are genuinely not a competitive intelligence product. If listening is the requirement, our write-up on Instagram social listening covers what that actually takes.

Part 7: When should you use a unified layer instead?

When you need Instagram alongside other platforms, or when the fields you need only exist behind the creator's own login. If Instagram is your only platform and you have an engineer to spend, build direct. Meta's API is free and the docs are good.

The case for a layer is not that Instagram is hard on its own. It is that every section of this guide repeats per platform, differently. TikTok has its own audit, a 24-hour token expiry and no webhooks. LinkedIn approval runs months. YouTube uses quota units where a search call costs a hundred times a metadata call. Four platforms is not four times the work, because normalisation grows faster than integration count. I compared all four in which platform API to integrate first.

That is what Phyllo's Instagram API removes. A creator connects through your product, we handle OAuth, the app review burden, token refresh, quota distribution and the polling, and you get normalised fields through the same schema serving 25+ platforms. The API reference is public if you would rather read endpoints than talk to anyone. Costs are in our Instagram API pricing breakdown.

The honest limit. We need the creator to connect. Someone who has not authorised anything does not appear in your data, through us or through Meta. If cold discovery is your workflow, that is a different category of tool and we say so in consent-based versus public social APIs.

Is the Instagram API free?

Meta charges no per call fee on any Instagram API. The cost is app review, business verification, a Professional account and roughly four to eight weeks of engineering.

What is the Instagram API rate limit?

For Instagram Platform endpoints it is 4,800 multiplied by the account's impressions over a rolling 24 hours. The flat 200 calls per hour figure is a legacy rule of thumb.

Is the Instagram Basic Display API still available?

No. Meta shut it down on 4 December 2024 and every endpoint returns an error. Use the Instagram API with Instagram Login for lightweight profile and media access.

Can I access a personal Instagram account through an API?

Not since December 2024. Both live APIs require a Professional account, meaning Business or Creator. Converting is free. Tools claiming otherwise breach Meta's terms.

Do I need a Facebook Page to use the Instagram API?

For the Graph API path, yes, and the account must be linked to a Page. The Instagram API with Instagram Login needs no Page, so check whether that path covers you first.

Why does publishing take three API calls?

Meta transcodes media asynchronously. You create a container, poll its status_code until it reads FINISHED, then publish by creation_id. Skipping the poll fails on real uploads.

Can I schedule Instagram Stories through the API?

Only for Business accounts. Content publishing covers all Professional accounts except Stories, which are Business only, so Creator account Stories cannot be scheduled.

What is the difference between an Instagram API key and an access token?

The App ID and App Secret identify your app and do not expire on a schedule. An access token is tied to one user, expires within 60 days, and exists only after OAuth approval.

Table of Content
See Phyllo in action
  • No Credit card required
  • GDPR & SOC2 Type II
  • 30-min Onboarding
Book a Demo

Be the first to get insights and updates from Phyllo. Subscribe to our blog.

Ready to get started?

Sign up to get API keys or request us for a demo