How to post Instagram carousels programmatically
A working integration path for posting Instagram carousels without the app — payload examples, scheduling patterns, and where plain API carts break down.
How to post Instagram carousels programmatically
TL;DR / Quick Answer: To post Instagram carousels programmatically in 2026, you make two sequential calls to Meta's Graph API: first, POST to
/{ig-user-id}/mediawithmedia_type: CAROUSEL_ALBUMand an ordered array ofchildrenimage URLs. Once the container status returnsFINISHED, POST to/{ig-user-id}/media_publishwith the resultingcreation_id. Alternatively, unified publishing APIs (like the engine powering Postim) compress this into a single payload with built-in scheduling and timezone normalization.
If you run content for a brand, "post the carousel" is a 20-minute manual routine: export 5 slides from your design tool, upload each in order, rewrite the caption for the platform, pick a time slot, repeat tomorrow. This guide is the shortest working path to making that a pipeline step — with the actual payload shapes, not screenshots. For architectural details on container parameters, also refer to our Instagram carousel API guide.
What "programmatically" actually requires
An Instagram carousel post is a container with 2–10 media children uploaded in order, published together. Anything that automates it must handle three things:
- Ordered media upload — slide 1 must land as slide 1. Instagram's graph API stamps carousel children only after all children are uploaded and the parent container is published.
- Caption + first-comment separation — many teams schedule the caption for the post and the hashtags for the comment; the API path must support both.
- Scheduled publishing — cron or a scheduler that carries a time zone per account, not per server.
The two viable paths (and the fake third)
| Path | What you get | Watch out for |
|---|---|---|
Meta official API (Instagram Business, media container with media_type=CAROUSEL_ALBUM) |
Fully legitimate, stable | Requires a Business account connected to a Facebook Page; works only per single IG account; 25 API-published posts per account per 24h. |
| Unified publishing API (Postim uses Late) | One integration → Instagram + more, scheduling built-in, per-account time zones | Third-party dependency — keep your media pipeline yours. |
The "fake third" people keep selling: unofficial download-and-repost bots on residential proxies. They work until the account safety review, then 6 months of audience-building is gone. For a business account, don't.
Reference payload: carousel container via Meta's API
POST https://graph.facebook.com/v21.0/{ig-user-id}/media
{
"media_type": "CAROUSEL_ALBUM",
"image_url": "https://cdn.yourapp.com/slides/slide-01.png",
"caption": "Why your top-of-funnel is quiet (and the 3 fixes we shipped)",
"children": [
{"image_url": "https://cdn.yourapp.com/slides/slide-01.png"},
{"image_url": "https://cdn.yourapp.com/slides/slide-02.png"},
{"image_url": "https://cdn.yourapp.com/slides/slide-03.png"}
]
}
Then poll the container for status_code: FINISHED and publish it:
POST https://graph.facebook.com/v21.0/{ig-user-id}/media_publish
{
"creation_id": "{container-id}"
}
This is exactly the machine that Postim runs for you after you plan, generate and approve the carousel — your slides leave the pipeline with the caption already filled in, and the publish step is a media_publish call with a time attached.
Reference payload: publishing through a unified API
The same carousel, as Postim sends it to Late (trimmed):
{
"platform": "instagram",
"postType": "carousel",
"mediaUrls": [
"https://cdn.postim.app/slides/slide-01.png",
"https://cdn.postim.app/slides/slide-02.png",
"https://cdn.postim.app/slides/slide-03.png"
],
"caption": "Why your top-of-funnel is quiet (and the 3 fixes we shipped)",
"scheduledAt": "2026-09-23T09:30:00-04:00"
}
One call, the scheduler handles the rest — including the two-step container dance above. Compare it against your current export-upload-caption-time-pick loop to see the delta.
Where teams usually get stuck
- Sequence tolerance. Instagram rejects carousels with mixed aspect ratios across children. Design your generator output to fit one frame — Postim's carousel generator defaults to a consistent 1080×1350 portrait loop for exactly this reason.
- Publishing slots. The Business-API limit (25 posts / 24h / account) is per-account, not per-app. If you manage 6 client accounts, that's 6 independent budgets — schedule accordingly.
- Time zones per account. A global team posting "9 AM" in UTC hits 4 AM in New York. Store the timezone with the account, not the job.
Frequently asked questions
Can I post Instagram carousels programmatically without the app?
Yes — with a Business account through Meta's official Graph API (two calls: a CAROUSEL_ALBUM container, then media_publish), or through a unified scheduling API. Both can be driven from your own backend or from Postim's pipeline.
How many images can an Instagram carousel have? Between 2 and 10. Every child must pass Instagram's mix-of-aspect-ratio tolerance, so keep all slides at the same ratio (1080×1350 portrait works best).
How often can I schedule Instagram posts via the API? Meta's official publishing limit is 25 API-published posts per Instagram account per 24 hours. The counter is per account, so multi-account teams have separate budgets.
What is the difference between Webhooks and Polling for container status?
Polling requires querying GET /{container-id}?fields=status_code every 5–10 seconds until it yields FINISHED. Webhooks via Meta App Dashboard send an asynchronous event when media processing concludes, reducing latency and API request count.
Where Postim fits
Postim is the layer above these APIs: you research the hook, generate the carousel, approve the slides, and the publish step fires on schedule. If you want to scale production beyond single posts, check out our 5-step loop to batch-create Instagram carousels with AI. If you're evaluating whether to build vs. buy the distribution layer, read our comparison of Instagram scheduling tools or try Postim free.