Skip to content
SocialHelper
Join waitlist
Developers

Instagram API: how to publish posts, reels and carousels in 2026

How the Instagram Graph API publishes: access, tokens, the container and publish calls, media limits, the daily cap Meta’s docs disagree on, and common errors.

11 minute read By SocialHelper team

The Instagram API lets an app post to Business and Creator accounts on Instagram, but not to personal ones. Meta calls it the Instagram Platform, and most developers still call it the Instagram Graph API. Publishing takes two calls. First you create a media container from a public image or video URL, then you publish it. Before that you need a Meta app and an access token with the publishing permission. If the app serves accounts you don’t manage, you also need App Review and Business Verification.

This guide covers access, tokens, the calls to publish, Meta’s limits and the errors you’ll meet. The worked example is the set of checks SocialHelper runs before it posts to Instagram.

What the Instagram API is

The Instagram Platform is Meta’s “collection of APIs that allows your app to access data for Instagram professional accounts including both businesses and creators” (Instagram Platform overview). It covers publishing, comments, messages and insights. The old Basic Display API, which read personal accounts, shut down on December 4, 2024. Meta said that afterwards “there will no longer be a set of Instagram APIs for consumer developer apps” (Meta for Developers blog).

There are two ways to set it up, and the choice decides your login, your API host and your permissions.

Instagram LoginFacebook Login
Accounts it servesProfessional accounts with no Facebook PageProfessional accounts linked to a Facebook Page
People sign in withInstagramFacebook
API hostgraph.instagram.comgraph.facebook.com
Permissions to publishinstagram_business_basic, instagram_business_content_publishinstagram_basic, instagram_content_publish, pages_read_engagement
Extra featuresNoneHashtag search, product tagging, partnership ads

Instagram Login is the simpler route if you only want to publish, and it’s the one SocialHelper uses. An app picks one: it can use Facebook Login or Instagram Login, but not both.

What you need before the first call

  1. A professional account. Switch the account to Business or Creator in the Instagram app. Personal accounts can’t be published to, and SocialHelper won’t connect one.
  2. A Meta app of the Business type. Create it in the Meta App Dashboard and add the Instagram product. If your existing app isn’t a Business app, Meta says “you will need to create a new app” (Get started with Instagram Login). The Instagram app ID and app secret are under Instagram, then API setup with Instagram business login.
  3. An access token for each account, covered in the next section.
  4. The right access level. Which one depends on whose accounts the app serves.

Standard Access is the default level, and it’s all you need when the app only serves your own accounts or ones you manage. There’s no review. Advanced Access is the level for an app that serves professional accounts you don’t own or manage, such as a scheduling tool. Meta’s overview says it “requires App Review and Business Verification”. For App Review you record a screencast, describe step by step how a person uses your app, and explain how you use each permission. Meta’s rule is that your app “must complete App Review before it can request permissions with Advanced Access from any app user” (App Review for Instagram API).

Instagram API keys and access tokens

Instagram has no API key. An access token is the credential every call carries. It says which app is calling, which account it acts for, what that account allowed and when it runs out. There are two ways to get one.

  • From the App Dashboard, for your own account. Click Generate token next to the account. These tokens are “long-lived and are valid for 60 days”.
  • Through Business Login for Instagram, for other people’s accounts. They sign in at instagram.com/oauth/authorize and you receive a code. Swap the code for a token that lasts 1 hour, then exchange that for a 60-day token with grant_type=ig_exchange_token (Business Login for Instagram).

Refresh a long-lived token with grant_type=ig_refresh_token before it runs out. Meta only refreshes a token that is “at least 24 hours old” and still valid. “Tokens that have not been refreshed in 60 days will expire and can no longer be refreshed.” Two details catch people out. The code Instagram sends back ends in #_, which “is not part of the code itself”, and the code is valid for one hour and works only once. SocialHelper strips the #_, renews each token in the week before it expires, and flags the account for reconnecting if Instagram refuses.

Publish a photo in two calls

A media container is Meta’s staging object for one post. You create it from a public URL, Meta downloads and processes the file, and nothing appears on Instagram until you publish it. Because Meta fetches the file itself, “the media must be hosted on a publicly accessible server at the time of the attempt” (Instagram content publishing guide).

First, create the container. Meta downloads the image from image_url and returns the container’s ID, which the next two calls use as $CONTAINER_ID.

curl -X POST "https://graph.instagram.com/v26.0/$IG_ID/media" \
  -H "Authorization: Bearer $IG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"image_url": "https://example.com/cinnamon-rolls.jpg",
       "caption": "Cinnamon rolls are back 🍂",
       "alt_text": "Fresh cinnamon rolls"}'

Next, check the container until its status_code is FINISHED.

curl "https://graph.instagram.com/v26.0/$CONTAINER_ID?fields=status_code" \
  -H "Authorization: Bearer $IG_TOKEN"

Then publish it, once. The response holds the new post’s media ID.

curl -X POST "https://graph.instagram.com/v26.0/$IG_ID/media_publish" \
  -H "Authorization: Bearer $IG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"creation_id\": \"$CONTAINER_ID\"}"

$IG_ID is the account’s Instagram user ID, which GET /me?fields=user_id,username returns. Version 26.0 is the newest Graph API, released on July 29, 2026 (Graph API changelog). Images must be JPEG. “JPEG is the only image format supported,” so convert PNG and WebP files before you send them.

Wait for the container, then publish once

Check the container’s status_code before you publish. It has five possible values (IG Container reference).

StatusMeaningWhat to do
IN_PROGRESSMeta is still processing the mediaWait and check again
FINISHEDReady to publishCall media_publish
ERRORProcessing failedRead the error subcode in status, fix the media, create a new container
EXPIREDNot published within 24 hoursCreate a new container
PUBLISHEDAlready liveDon’t publish it again

Meta recommends checking “once per minute, for no more than 5 minutes”. Images are usually ready much sooner, so SocialHelper checks images every 2 seconds for up to 30 seconds and videos every 10 seconds for up to 3 minutes. If Meta is still working after that, the post is tried again later from the start.

The hard case is a publish call that times out. The post may or may not be live, and calling media_publish again could post it twice. SocialHelper treats a timeout there as an unknown outcome. It looks for the post among the account’s latest media before trying again, and it never publishes a container that already reports PUBLISHED. The guide to idempotent APIs explains the pattern.

Reels, carousels and stories

  • Reels. Create the container with media_type=REELS and a video_url. The optional share_to_feed lets the reel show in the main feed too, not just the Reels tab. thumb_offset picks the cover frame, in milliseconds. A published reel reports its media_type as VIDEO, so ask for media_product_type to tell reels apart.
  • Carousels. Create a container for each image or video with is_carousel_item=true and no caption. Then create a carousel container with media_type=CAROUSEL, the caption and children set to up to 10 container IDs, and publish that one. Meta crops every image to the first one’s shape, and a reel can’t go in a carousel.
  • Stories. Use media_type=STORIES. Story videos can run 60 seconds and 100 MB at most. SocialHelper publishes feed posts, reels and carousels, but not stories.

Two newer options apply to every type. Since June 22, 2026, is_ai_generated=true adds Meta’s AI info label, set on the carousel container only for carousels. Since December 3, 2025, DELETE /{ig_media_id} removes a post, with the new instagram_manage_contents permission (Instagram Platform changelog).

Media and caption limits

These limits come from Meta’s reference for creating media (IG User Media reference).

WhatLimit
Image formatJPEG only
Image file size8 MB
Image aspect ratio4:5 (portrait) to 1.91:1 (landscape)
Image width320 to 1,440 pixels, scaled by Meta outside that range
Reel formatMOV or MP4, H.264 or HEVC video, AAC audio
Reel length and size3 seconds to 15 minutes, up to 300 MB
Reel frame rate23 to 60 frames per second
Story video3 to 60 seconds, up to 100 MB
CarouselUp to 10 images and videos
Caption2,200 characters, 30 hashtags, 20 @ mentions
Alt text1,000 characters, images only

SocialHelper checks the format, file size, aspect ratio, carousel, caption and alt text rules before anything is sent. It reports every problem at once, so a post never fails halfway through on Instagram. The hashtag limit is changing. Instagram said in December 2025 that it would cut the hashtags allowed in a post to five (Social Media Today), while the API reference still lists 30. The Instagram character counter counts a caption the way Instagram does.

How many posts a day? Ask the API

Meta’s docs give two answers here. The publishing guide says “Instagram accounts are limited to 100 API-published posts within a 24-hour moving period”. Further down, under carousels, it says “Accounts are limited to 50 published posts within a 24-hour period.” The reference for the limit endpoint gives the quota as “currently 50” (Content Publishing Limit reference). Some older guides still quote 25.

So ask the account. GET /$IG_ID/content_publishing_limit?fields=config,quota_usage returns how many posts it has published in the last 24 hours and its quota_total. A carousel counts as one post. SocialHelper reads the limit before it creates any container. When an account has used it up, the post waits an hour and tries again instead of failing.

Other calls have their own budget. Meta’s overview gives it as “Calls within 24 hours = 4800 * Number of Impressions”, where impressions count how often the account’s content was seen in the last 24 hours.

Errors you’ll meet

Failed calls return an error code and a subcode. These are the subcodes that come up most when publishing (Instagram error codes).

SubcodeWhat it meansFix
2207004Image larger than 8 MBSend a smaller image
2207005Image format not supportedConvert it to JPEG
2207009Aspect ratio out of rangeCrop to between 4:5 and 1.91:1
2207010Caption too longShorten the caption
2207026Video format not supportedRe-encode as MP4 or MOV
2207052Meta couldn’t fetch the media URLMake the URL public
2207027Media not ready yetWait for FINISHED, then publish
2207042Daily publishing limit reachedTry again the next day
2207051Blocked as possible spamDon’t retry; tell Meta if it’s a mistake

SocialHelper turns each of these into a plain message on the post. It retries the ones Meta marks as temporary, such as server errors, download timeouts and a container that expired or wasn’t ready, with a new container. The rest fail with the reason.

The shortcut: one API for Instagram and the rest

If you’d rather not build the token refresh, the status checks and the limit handling yourself, SocialHelper does them for you. Connect the Instagram account once in the dashboard, with no Facebook Page needed. Upload the image to /api/v1/media, then send one request with its ID.

curl https://socialhelper.app/api/v1/posts \
  -H "Authorization: Bearer $SOCIALHELPER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
      "text": "Our cinnamon rolls are back for autumn 🍂",
      "accounts": [
          "INSTAGRAM_ACCOUNT_ID"
      ],
      "media": [
          "MEDIA_ID"
      ]
  }'

That’s the whole request. The same call can post to other connected accounts at once, set a time with scheduled_at or add the post to your queue. Upload and import options are in the media docs, and the Instagram integration page lists what SocialHelper supports. AI assistants use the same actions through MCP, and the MCP vs API guide shows the difference. To pick a slot, see the best time to post on Instagram.

Frequently asked questions

Is the Instagram API free?

Meta’s Instagram Platform docs list no price for publishing to or reading your accounts. The costs are elsewhere: App Review and Business Verification if you serve other people’s accounts, and the daily publishing limit.

Does Instagram have an upload API?

Yes. The content publishing API creates a container from an image or video URL and publishes it. Apps that use Facebook Login can also send large videos through Meta’s resumable upload host, rupload.facebook.com.

How do I get an Instagram API key?

There isn’t one. Create a Business type Meta app, add the Instagram product, and generate an access token for your professional account in the App Dashboard. It lasts 60 days and can be refreshed.

How do I find my Instagram app ID?

In the Meta App Dashboard, open your app, then Instagram, then API setup with Instagram business login. The Instagram app ID and app secret are shown there.

Can the Instagram API post to a personal account?

No. Publishing works only for Business and Creator accounts, and the Basic Display API for personal accounts ended in December 2024.

Can you schedule posts with the Instagram API?

Not directly. Meta’s reference has no way to set a time, so your app calls media_publish when the post should go out. Meta suggests enforcing the publishing limit yourself, “especially if your app allows app users to schedule posts to be published in the future”. SocialHelper schedules posts this way and checks the limit first.

How we checked this

We read Meta’s Instagram Platform docs on October 17, 2026, and ran a fact check of every limit and quote against them. That covered the overview, the publishing guide, Business Login, App Review, the error codes and the references for media, containers and the publishing limit. We analyzed SocialHelper’s Instagram integration on October 17, 2026 for the behaviour described here, and the example request is tested against Instagram’s rules in our test suite.

If you spot something that has changed, contact us and we’ll correct it.

Post everywhere from one place.

SocialHelper is invite-only during early access. Join the waitlist: the first 100 people to sign up get a Founding account with higher limits, free for 12 months.