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.
The Instagram Content Publishing API posts in two steps: you create a media container with POST /{ig-user-id}/media, then publish it with POST /{ig-user-id}/media_publish. The same flow covers single images, reels, carousels of up to 10 items and stories, on both Instagram Login and Facebook Login, and Meta's own GitHub sources state three different daily caps: 100, 50 and 25 posts.
This guide belongs to Meta API use cases: which one your app needs. It is built from Meta's official GitHub repositories (the Instagram Platform Postman collection, the Reels publishing sample and the Python Business SDK) and from our own Instagram changelog entries. Where those sources disagree, the page says so.
What this means for you
When a scheduling tool posts to Instagram for you, it first hands Instagram your photo or video, then tells Instagram to post it. Instagram fetches the file from a public web address, so the tool has to host it. You need a Business or Creator account, and every account has a daily limit on posts made this way.
The details: how the Instagram Content Publishing API works
Container, then publish
Every format follows the same steps:
- Create a container.
POST /{ig-user-id}/mediawithimage_urlorvideo_url, an optionalcaption, andmedia_typefor anything that isn't a single image. The response is{ "id": "<IG_CONTAINER_ID>" }. - Wait for video to finish. For video, read
GET /{container-id}?fields=status_codeuntil it returnsFINISHED. - Publish.
POST /{ig-user-id}/media_publishwithcreation_idset to the container ID. The response is the new media ID.
POST https://graph.instagram.com/{api-version}/{ig-user-id}/media
image_url=<PUBLIC_JPEG_URL>
caption=<CAPTION>
→ { "id": "<IG_CONTAINER_ID>" }
POST https://graph.instagram.com/{api-version}/{ig-user-id}/media_publish
creation_id=<IG_CONTAINER_ID>
→ { "id": "<IG_MEDIA_ID>" }
Meta's guide says it cURLs the media, so the file "must be hosted on a publicly accessible server at the time of the attempt". The container's status_code takes one of five values:
status_code | What Meta's guide says it means |
|---|---|
IN_PROGRESS | Still in the publishing process |
FINISHED | Ready to publish |
PUBLISHED | Already published |
ERROR | Failed to complete the publishing process |
EXPIRED | Not published within 24 hours |
The guide recommends checking a container's status once per minute for no more than 5 minutes. Meta's Reels sample app polls faster: every 3 seconds, giving up after about 90 seconds. Both are Meta's own code, so pick an interval that fits your video sizes and watch your call budget (see Meta Graph API rate limits).
Both login paths
| Instagram Login | Facebook Login | |
|---|---|---|
| Host | graph.instagram.com | graph.facebook.com |
| Token in Meta's examples | Instagram User access token | Page access token in the Postman requests; the Facebook user token in the Reels sample app |
| Permissions in Meta's examples | instagram_business_basic, instagram_business_content_publish | instagram_basic, instagram_content_publish, pages_show_list, pages_read_engagement, plus business_management in the Reels sample |
| Facebook Page | Not needed | Must be linked to the Instagram account |
Which path to build on, and why, is covered in Instagram Login or Facebook Login?. Token lifetimes are in Meta access tokens.
One trap if you use the Python Business SDK: on the Instagram Login class, the publish call points at /mediapublish, while the Facebook Login class and every Postman request use /media_publish. Test that call before you rely on the SDK for Instagram Login.
Formats: images, reels, carousels and stories
| Format | Container settings | What Meta's sources add | Last change on our changelog |
|---|---|---|---|
| Image | image_url | JPEG only; MPO and JPS aren't supported | AI info label, June 22, 2026 |
| Reel | media_type=REELS, video_url or upload_type=resumable | share_to_feed, cover_url, thumb_offset | AI info label, June 22, 2026 |
| Carousel | One container per item with is_carousel_item=true, then media_type=CAROUSEL with children | Up to 10 items; one caption on the carousel container | AI info label, June 22, 2026 |
| Story | media_type=STORIES with video_url in Meta's examples | Business accounts only on Facebook Login | Trial Reels and media deletion, December 3, 2025 |
Instagram API: publish reels
Set media_type=REELS and pass the video. The VIDEO media type stopped working on November 9, 2023. One Meta source hasn't caught up: the Postman collection's image container description still lists VIDEO as an option, while its video request, updated the same day, lists only REELS and STORIES.
share_to_feed=trueputs the reel in both Feed and the Reels tab;falsekeeps it in the Reels tab only.cover_urlis a public image for the Reels tab cover.thumb_offsetpicks a frame in milliseconds (default0). If you send both,cover_urlwins.- Video specs in Meta's Reels sample: MOV or MP4, AAC audio at up to 48 kHz, HEVC or H.264 video, 23 to 60 FPS, at most 1920 horizontal pixels, 9:16 recommended, video bitrate up to 25 Mbps, audio bitrate 128 kbps, 3 seconds to 15 minutes, 1 GB at most.
- A published reel returns
media_typeVIDEO. Readmedia_product_typeto tell reels apart. - Newer options:
trial_paramsfor Trial Reels, and audio from the Instagram Audio API, which our entry lists as Facebook Login.
Instagram API: carousel posts
A carousel takes one call per item plus two more. Create a container for each image or video with is_carousel_item=true. Then create the carousel container with media_type=CAROUSEL, children set to a comma-separated list of up to 10 container IDs, and the caption. Publish the carousel container once. Meta's collection says carousel images are all cropped based on the first image, 1:1 by default. If you label AI content, our entry on is_ai_generated says it goes on the carousel container only.
Stories
Set media_type=STORIES. Meta's Postman request and its Reels sample both create a video story; neither shows an image story. The collection's Facebook Login description says content publishing works for all professional accounts "except Stories, which are only available to business accounts". It says nothing on this for Instagram Login.
Large videos: resumable upload
Instead of a video_url, you can create the container with upload_type=resumable. Meta's Reels sample shows what happens next: the response carries the container ID and a uri, and the app posts the video file to that address on rupload.facebook.com with the headers Authorization: OAuth <token>, offset: 0 and file_size. Then it polls and publishes as usual. The README says to use a video URL or a file, not both.
Meta's sources disagree on who can use this. The Postman collection's publishing guide says resumable upload is "only for apps that have implemented Facebook Login for Business", yet that guide is for Instagram Login and its own story request sends upload_type=resumable to graph.instagram.com. The Python SDK accepts upload_type on both login classes.
What isn't supported
The collection's Instagram Login publishing guide lists: image formats other than JPEG, shopping tags, branded content tags and filters. The two SDK classes also differ: the Facebook Login media call accepts parameters the Instagram Login one doesn't, including is_paid_partnership and branded_content_sponsor_ids (the paid partnership label), cross_post_to_threads and poll_attachment. Meta's GitHub sources don't describe the last two, so treat them as unconfirmed.
Instagram publishing limit: 100, 50 or 25 posts a day?
| Source | What it says | Written |
|---|---|---|
| Postman collection, publishing guide | 100 API-published posts within a 24-hour moving period; a carousel counts as one | September 10, 2025 |
| Postman collection, carousel request | 50 published posts within a 24-hour period; a carousel counts as one | September 10, 2025 |
| Reels sample README | 25 API-published posts within a 24-hour moving period | February 14, 2023 |
The dates come from the git history of each line. The two newer figures were written in the same commit and still disagree. The 100 and 25 figures both say the limit is enforced on media_publish, not on container creation, and the guide asks apps to enforce it themselves, "especially if your app allows app users to schedule posts to be published in the future".
Checking content_publishing_limit
Don't hard-code any of the three numbers. Ask the account:
GET /{ig-user-id}/content_publishing_limit?fields=config,quota_usage
Meta's Reels sample reads data[0].config.quota_total and data[0].quota_usage and subtracts one from the other to show the publishes left. The Python SDK offers this call on both login classes and accepts an optional since date. The sample also calls it right after login, using the response code to check that each account has access to content publishing at all.
Schedule Instagram posts with the API
There is no publish-time parameter. Neither SDK class lists one on its media creation call, so scheduling is your app's job: store the post, then create the container and publish it when it's due. Since an unpublished container expires after 24 hours, don't create it more than a day ahead. Count your own publishes against the account's quota before you queue more.
The Facebook Login class in the SDK also has a read-only GET /scheduled_media edge (caption, media type, media URL, publish_timestamp, thumbnail). Meta's GitHub sources don't say how media gets there, so don't build a scheduler on it. For the non-developer side, see how to schedule Instagram posts, and check caption length with the character counter.
Errors and status checks
Meta's GitHub sources point to an error codes reference but list no publishing error codes, so this page doesn't either. What they do show:
- The container's
statusfield carries a readable message next tostatus_code, such as "Finished: Media has been uploaded and it is ready to be published." - Meta's Reels sample reads
id,status,status_code,video_statuswhile a resumable upload runs. In the SDK,video_statushasuploading_phaseandprocessing_phase, and the container also hascopyright_check_statuswithstatusandmatches_found. - If you re-read media after publishing,
media_urlcan be missing: since July 30, 2026 it is left out for protected or download-disabled media.
To hear about new comments and messages instead of polling for them, see Meta webhooks.
Changes by date
- 2022-06-28: Reels publishing added, with
media_type=REELS. - 2023-11-09:
VIDEOstops working for publishing. - 2024-07-23: Instagram Login launches, with no Page needed.
- 2025-01-27: Old Instagram Login scopes stop working; use
instagram_business_content_publish. - 2025-12-03: Trial Reels and
DELETE /{ig_media_id}. - 2026-04-22: Paid partnership label and collaborative media.
- 2026-06-01: Audio API for Reels (Facebook Login).
- 2026-06-22:
is_ai_generatedon both logins. - 2026-07-30:
media_urlomitted for protected media.
All Instagram changes are on the Instagram network page, and API versions are in Instagram API versions. Threads has its own publishing flow: see Threads API publishing.
What to do next
- Business owners: Use a Business account if you want to schedule Stories through a tool that connects with Facebook. A tool can't publish more than your account's daily quota, whatever its plan says.
- Marketers and agencies: Ask your tool how it handles the daily cap and failed posts, and whether it supports Stories and carousels for your account type.
- Developers: Read
content_publishing_limitbefore each publish, poll container status beforemedia_publish, create containers less than 24 hours ahead, useREELS(neverVIDEO), and plan for Advanced Access through Meta App Review if you'll publish for accounts you don't manage.
Questions people ask
How many posts a day can the Instagram API publish?
Meta's GitHub sources give three numbers. Its Postman collection says 100 API-published posts in a 24-hour moving period in its publishing guide and 50 in its carousel request, both added in September 2025; its Reels sample, written in February 2023, says 25. A carousel counts as one post. Read the account's real quota from content_publishing_limit instead of hard-coding any of them.
How many items can an Instagram API carousel have?
Up to 10 images, videos or a mix of the two. You create one container per item with is_carousel_item set to true, then a carousel container with media_type CAROUSEL and the item IDs in children, and you publish that one container. Meta's collection says carousel images are all cropped based on the first image, 1:1 by default.
Can you schedule Instagram posts with the API?
Not with a publish-time setting: neither of the Python SDK's media creation calls takes one. Your app stores the post and runs the container and publish steps when it is due. Meta's guide says an unpublished container expires after 24 hours and recommends that apps which schedule posts enforce the daily limit themselves.
Can the Instagram API publish Stories?
Yes, with media_type set to STORIES on the container. Meta's Postman collection says that on the Facebook Login path Stories publishing is only available to business accounts, not creator accounts. It doesn't say whether the same rule applies to Instagram Login.
Why does a reel I published come back as media_type VIDEO?
That's expected. Meta's collection says a published reel returns VIDEO in media_type, and that you read media_product_type to tell whether a video is a reel. You still create it with media_type REELS, since the VIDEO publishing type stopped working on November 9, 2023.
Sources
- Meta on GitHub: Instagram Platform API Postman collection (fbsamples/messenger-platform-samples)
- Meta on GitHub: Instagram Reels publishing sample README (fbsamples/reels_publishing_apis)
- Meta on GitHub: Instagram Reels publishing sample app code (fbsamples/reels_publishing_apis)
- Meta on GitHub: Python Business SDK, IG User (Facebook Login)
- Meta on GitHub: Python Business SDK, IG User for the Instagram Login API
- Meta on GitHub: Python Business SDK, media container (ShadowIGMediaBuilder)
- Meta on GitHub: Python Business SDK, content publishing limit response
- Meta for Developers: Instagram Platform changelog (as recorded in our changelog entries)
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
Meta access tokens: Instagram, Facebook Page and Threads
Meta access tokens for Instagram, Facebook Pages and Threads: what Meta's own code and Postman collections show, and the token lifetimes they leave unstated.