Instagram API guide
Instagram API guide: publishing Reels, photos, carousels and Stories
Instagram's content publishing API posts Reels, photos, carousels and Stories to Instagram professional accounts (business or creator), never to personal ones. Every post is a container that you create from a public media URL, wait for and then publish. Your app needs Meta's App Review and Business Verification before it can post for accounts it does not own or manage. This guide sums up Meta's own developer pages, read on 15 October 2026.
- Sources read on
- Checked on
Who can publish: professional accounts only
Meta states it plainly: "To use the APIs, your app users must have an Instagram professional account." A professional account can be a business account or a creator account. Personal accounts cannot publish by API. [I7]
The Instagram Basic Display API, which read personal accounts, was deprecated on 4 December 2024. There is no API path left for personal Instagram accounts. [I10]
If the Facebook Page connected to the account requires Page Publishing Authorization (PPA) or two-factor authentication, publishing fails until the person behind the Page has completed it. [I1, I2, I3]
Two ways in: Instagram Login or Facebook Login for Business
| Item | Instagram API with Instagram Login | Instagram API with Facebook Login for Business |
|---|---|---|
| Host | graph.instagram.com, with an Instagram User token | graph.facebook.com (and rupload.facebook.com for resumable video) |
| Facebook Page | Not needed | Required: "your app users' Instagram professional accounts must be connected to a Facebook Page" |
| Publishing permissions | instagram_business_basic and instagram_business_content_publish | instagram_basic, instagram_content_publish and pages_read_engagement (plus ads_management or ads_read when the Page role comes from Business Manager) |
| Only on this path | Not listed | Resumable video upload, hashtag search, product tagging, Partnership Ads |
- Meta's permissions reference describes the publishing permission in both forms the same way: it "allows your app to create organic feed photo and video posts on behalf of a business user." [I11]
- Meta's App Review page for Instagram adds: "Web or mobile Web is the only platform that currently supports Instagram API with Instagram Login." [I8]
Access levels, App Review and Business Verification
Standard Access is the default. As soon as your app serves Instagram accounts that you do not own or manage, it needs Advanced Access, and in Meta's words, "This access level requires App Review and Business Verification." [I7]
App Review is requested permission by permission. For each one you describe how the app uses it, record a screencast of the end-to-end use, and give test credentials with step-by-step instructions for Meta's reviewers. Meta notes: "To request Advanced Access to certain permissions, you need to make at least 1 successful API call." Requests for permissions the app does not use are not approved. [I8]
How long App Review and Business Verification take: not listed. Neither Meta's App Review page for Instagram nor its general App Review page gives a time. [I8]
Sign-in and tokens (Instagram Login)
- Business Login for Instagram sends the person to https://www.instagram.com/oauth/authorize. The authorization code it returns "is valid for 1 hour and can only be used once." [I9]
- The long-lived token you get from it is "valid for 60 days". [I9]
- A long-lived token can be refreshed once it is at least 24 hours old and has not expired. Meta warns: "Tokens that have not been refreshed in 60 days will expire and can no longer be refreshed." [I9]
- The old scope names (business_basic, business_content_publish and the rest) were deprecated on 27 January 2025; use the instagram_business_* names. [I9, I10]
- Expired or invalid tokens answer the standard Graph API error 190; missing permissions answer 10 or a code from 200 to 299. [I12]
Publishing step by step: containers
- Create a container: POST /<IG_ID>/media with image_url for a photo, or video_url with media_type REELS or STORIES for a video. Meta fetches the file itself: "We cURL media used in publishing attempts, so the media must be hosted on a publicly accessible server at the time of the attempt." [I1, I2]
- For a carousel, create one container per item with is_carousel_item=true, then a parent container with media_type=CAROUSEL and children set to up to 10 container ids. [I1, I2]
- Wait for the container: GET /<IG_CONTAINER_ID>?fields=status_code answers EXPIRED, ERROR, FINISHED, IN_PROGRESS or PUBLISHED. "Video uploads are asynchronous, so receiving a container ID does not guarantee that the upload was successful." Meta recommends "querying a container's status once per minute, for no more than 5 minutes." [I1, I2, I5]
- Publish it: POST /<IG_ID>/media_publish with creation_id set to the container id. The answer is the id of the published media. [I3]
- Videos on the Facebook Login path can also go up in pieces instead of by URL: create the container with upload_type=resumable, then POST the bytes to https://rupload.facebook.com/ig-api-upload/<API_VERSION>/<IG_MEDIA_CONTAINER_ID> with an Authorization header of the form OAuth <ACCESS_TOKEN>, plus offset and file_size for a local file, or file_url for a hosted one. Meta: "Only for apps that have implemented Facebook Login for Business." [I1]
curl -X POST 'https://graph.instagram.com/v25.0/{ig-user-id}/media' \
-d 'media_type=REELS' \
-d 'video_url=https://example.com/clip.mp4' \
-d 'caption=Behind the scenes #studio' \
-d 'access_token={instagram-user-access-token}'
# When GET /{container-id}?fields=status_code answers FINISHED:
curl -X POST 'https://graph.instagram.com/v25.0/{ig-user-id}/media_publish' \
-d 'creation_id={container-id}' \
-d 'access_token={instagram-user-access-token}'What a container can carry
Besides the media, Meta's IG User Media reference lists the fields below. Which ones a post type takes differs, so check the reference for each type before you send one. [I2]
- caption: "Maximum 2200 characters, 30 hashtags, and 20 @ tags." [I2]
- Reels: cover_url (a cover image), thumb_offset ("Location, in milliseconds, of the video or reel frame to be used as the cover thumbnail image."), share_to_feed, audio_name and trial_params for Trial Reels. [I2]
- collaborators: "A list of up to 3 instagram usernames", on photos, Reels and carousels; location_id; and user_tags to tag people. [I2]
- alt_text: alternative text for image posts, up to 1,000 characters; not for Reels or Stories. [I2, I1]
- is_ai_generated: Instagram's self-disclosure for AI-generated content. On a carousel it goes on the parent container only; on a child it is an error. [I1, I10]
Media specs
| Type | Meta's rule |
|---|---|
| Images | "JPEG is the only image format supported." Up to 8 MB; aspect ratio 4:5 to 1.91:1; 320 to 1,440 pixels wide (other widths are scaled). |
| Reels | MOV or MP4 with the moov atom at the front and no edit lists; HEVC or H.264; AAC audio up to 48 kHz; 23 to 60 frames a second; up to 1,920 pixels wide; aspect ratio 0.01:1 to 10:1 (9:16 recommended); video up to 25 Mbps; 3 seconds to 15 minutes; up to 300 MB. |
| Stories | Video of 3 to 60 seconds and up to 100 MB, aspect ratio 0.1:1 to 10:1; images up to 8 MB; 9:16 recommended. |
| Carousels | 2 to 10 images or videos. "Carousel images are all cropped based on the first image in the carousel, with the default being a 1:1 aspect ratio." Reels cannot appear in carousels. |
| Not supported | Shopping tags and filters; Story stickers such as links, polls and locations. |
Limits and rate limits
Meta's own pages disagree on the publishing limit. The Content Publishing guide says in one place "Instagram accounts are limited to 100 API-published posts within a 24-hour moving period" and, under carousels, "Accounts are limited to 50 published posts within a 24-hour period." The Media Publish reference says 50 in a 24-hour moving period, and the Content Publishing Limit reference calls 50 the current quota_total. Carousels count as one post. [I1, I3, I4]
- Read the live number instead of guessing: GET /<IG_ID>/content_publishing_limit returns quota_usage and a config with quota_total and quota_duration (86,400 seconds). [I4]
- Containers: "An Instagram account can only create 400 containers within a rolling 24 hour period", and "Containers expire after 24 hours" if they are not published. [I2]
- API calls: Business Use Case rate limiting, where "Calls within 24 hours = 4800 * Number of Impressions". [I7]
Errors Instagram returns
| Code / subcode | What it means | What to do |
|---|---|---|
| 9 / 2207042 | The account reached the maximum number of posts the API may publish. | Wait until the 24-hour window frees a slot. |
| 9007 / 2207027 | "The media is not ready for publishing, please wait for a moment" | Publish only once status_code is FINISHED. |
| 9004 / 2207052 | "The media could not be fetched from this uri" | Use a public, valid URL that stays up. |
| -2 / 2207003 | "It takes too long to download the media." | Retry. |
| 24 / 2207008 | The creation id does not exist or has expired. | Retry briefly, then make a new container. |
| -2 / 2207020 | The media expired. | Make a new container. |
| 36000 / 2207004 | The image is too large (over 8 MiB). | Send a smaller image. |
| 36001 / 2207005 | The image format is not supported. | Send a JPEG. |
| 36003 / 2207009 | The aspect ratio is outside 4:5 to 1.91:1. | Crop or pad the image. |
| 36004 / 2207010 | The caption is too long (2,200 characters, 30 hashtags, 20 @ tags). | Shorten it. |
| 352 / 2207026 | "The video format is not supported" | Send MOV or MP4. |
| 100 / 2207028 | A carousel needs 2 to 10 items. | Fix the number of children. |
| 25 / 2207050 | "The Instagram account is restricted." | The person signs in to the Instagram app and completes what it asks. |
| 4 / 2207051 | Activity restricted to protect the community. | Not listed. |
Sources: [I6]
- Server and upload errors (-1 with subcodes 2207001, 2207032 or 2207053) are worth a retry, then a new container. Subcode 2207023 is an unknown media type, and 2207040 is more than 20 @ tags. [I6]
What changed in 2025 and 2026
- 21 January 2025: Insights for Instagram Login apps, with the new views metric; several media metrics and the Instagram v1.0 endpoints deprecated. 27 January 2025: the old Instagram Login scope names stopped. 24 March 2025: alt_text for image posts. [I10, I1]
- 14 June 2025: force_reauth for Business Login for Instagram. 9 July 2025: user_tags on image and video Stories. [I10, I2]
- 3 December 2025: Trial Reels (trial_params), a Delete Instagram Media endpoint (instagram_manage_contents) and collaboration invites. [I10]
- 22 April 2026: the Collaborative Media API and the Partnership Ads label at publish time. 1 June 2026: the Instagram Audio API for Reels (Facebook Login). 22 June 2026: is_ai_generated, a self-disclosure on content publishing. [I10]
- Graph API v26.0 came out on 29 July 2026. v20.0 was removed on 24 September 2026, and v21.0 goes on 21 January 2027. [I13]
Gotchas developers hit
- A container id is not a published post. Publish only after status_code says FINISHED, or the call fails with 9007 / 2207027. [I1, I2, I6]
- Your media URL must stay public until Meta has fetched it. Meta recommends US-ASCII URLs, "or the request will fail". [I1, I2]
- Meta's docs list JPEG as the only image format for feed photos and carousels. [I1]
- Unpublished containers expire after 24 hours, and an account can create only 400 of them in a rolling 24 hours, so do not create containers far ahead of the post. [I2]
- thumb_offset is in milliseconds, not seconds. [I2]
- A published Story reads back with media_type IMAGE or VIDEO, and a Reel with VIDEO. Use media_product_type to tell them apart. [I1]
- Resumable upload exists only on the Facebook Login path; with Instagram Login, video goes up by URL. [I1]
Posting to Instagram through Status 200 Uploads
Status 200 Uploads publishes to Instagram with its own Meta app: you sign in on Instagram itself and never create a Meta developer app or go through the App Review and Business Verification above. The facts below are the ones our Instagram page shows, as checked on that page's own date.
- What you can post
- A Reel (one video), a feed post with one photo, or a carousel of 2 to 10 files.
- Largest video
- 300 MB per file. File limits of every network
- Largest image
- 8 MB per image.
- Reel length
- Up to 15 minutes, Instagram's own limit for Reels published from an app.
- Caption
- Up to 2,200 characters. A dry run or a scheduled post flags a longer caption (caption_over_limit) before Instagram sees it.
- Account type
- A Business or Creator account: Instagram does not let apps publish to a personal account.
- Daily allowance
- Instagram counts the posts an account publishes in a rolling window. The account's posting options show how many are used and how many are left.
- Scheduling
- Schedule a post up to 365 days ahead, or send it now.
- Your own Meta app
- Not needed. Every post is published by our own Meta app, so you never create one or wait for Meta to review it.
Settings you can choose: Post type, Reel cover.
Instagram API questions
Yes, to Instagram professional accounts (business or creator), with the content publishing endpoints of Meta's Instagram Platform: create a container, wait until it is FINISHED, then publish it.
No. Meta requires an Instagram professional account for publishing, and the Basic Display API for personal accounts was deprecated on 4 December 2024.
Not with Instagram Login, which uses graph.instagram.com and an Instagram User token. With Facebook Login for Business, the Instagram account must be connected to a Facebook Page.
Meta's pages disagree: the Media Publish reference says 50 in a 24-hour moving period, and the Content Publishing guide says 100 in one place and 50 in another. GET /<IG_ID>/content_publishing_limit gives the live number. A carousel counts as one post.
The container is not ready to publish. Check its status_code and publish once it is FINISHED; Meta suggests checking once a minute for up to 5 minutes.
3 seconds to 15 minutes, up to 300 MB, as MOV or MP4 with H.264 or HEVC video.
With Instagram Login: instagram_business_basic and instagram_business_content_publish. With Facebook Login for Business: instagram_basic, instagram_content_publish and pages_read_engagement. Serving accounts you do not own or manage needs Advanced Access, which requires App Review and Business Verification.
Long-lived Instagram Login tokens last 60 days. You can refresh one once it is at least 24 hours old; a token not refreshed within 60 days expires for good.
More on Instagram
Instagram's own pages
Sources read on 15 October 2026.
- I1Content Publishing (no date shown)
- I2IG User Media reference (no date shown)
- I3IG User Media Publish reference (no date shown)
- I4IG User Content Publishing Limit reference (no date shown)
- I5IG Container reference (no date shown)
- I6Error Codes (no date shown)
- I7Instagram Platform overview (no date shown)
- I8App Review for Instagram (no date shown)
- I9Business Login for Instagram (no date shown)
- I10Instagram Platform changelog (last updated newest entry June 22, 2026)
- I11Permissions reference (no date shown)
- I12Graph API error handling (no date shown)
- I13Graph API changelog (no date shown)
Post to Instagram without building it yourself
Instagram is on every plan, Free included. This page was checked on 26 October 2026.