How to Publish Instagram Reels via API: Upload, Schedule, and Automate Short-Form Video
A deep technical guide to publishing Instagram Reels through Meta's Content Publishing API — container creation, video specs, cover images, audio limitations, and common errors.
Why Reels get their own guide
The Instagram integration guide covers the full Content Publishing API — images, videos, carousels, stories. But Reels have enough unique requirements (video specifications, cover image handling, audio constraints, duration quirks) that developers keep hitting the same problems.
This guide covers the Reels-specific publishing flow in detail. If you need the broader Instagram API overview, start with the integration guide first.
Before you start: account type and permissions
Reels publishing through the API only works with Instagram Business accounts. Creator accounts are not supported for content publishing via the API — this is a common source of confusion.
Your app needs these permissions approved through Meta’s app review:
instagram_business_basic— access basic account informationinstagram_business_content_publish— create and publish media
These replaced the older instagram_basic and instagram_content_publish scopes, which were deprecated on January 27, 2025. If your app still references the old scope names, update them before submitting for review.
Each permission requires a separate app review submission with a screencast demonstrating the complete user flow. Expect 2–4 weeks for review.
The Reels publishing flow
Like all Instagram content, Reels use the container model — create a container, wait for processing, then publish. But Reels add an important middle step that you cannot skip.
Step 1 — Create the container
POST to /{ig-user-id}/media:
{ "media_type": "REELS", "video_url": "https://example.com/video.mp4", "caption": "Your caption text", "cover_url": "https://example.com/cover.jpg", "share_to_feed": true}The video_url must point to a publicly accessible file. Meta’s servers fetch the video from your URL directly — there is no direct file upload through the standard container flow.
For large files or unreliable hosting, use the resumable upload flow instead. POST to /{ig-user-id}/media with upload_type set to resumable and media_type set to REELS, then upload the binary to https://rupload.facebook.com/ig-api-upload/{api-version}/{ig-container-id}.
Returns: {"id": "<CONTAINER_ID>"}
Step 2 — Poll for processing status
This step is critical. Do not skip it.
GET /{container-id}?fields=status_code:
{ "status_code": "IN_PROGRESS", "id": "<CONTAINER_ID>"}Wait until status_code returns FINISHED. If you call the publish endpoint before the container is ready, you get a 400 error.
Possible status values:
| Status | Meaning |
|---|---|
IN_PROGRESS | Video is still being processed |
FINISHED | Ready to publish |
PUBLISHED | Already published |
EXPIRED | Not published within 24 hours |
ERROR | Processing failed |
Meta recommends polling once per minute for no more than 5 minutes. In practice, most Reels containers finish processing within 30 seconds to 2 minutes depending on file size and server load.
Step 3 — Publish
POST to /{ig-user-id}/media_publish:
{ "creation_id": "<CONTAINER_ID>"}Returns the published Instagram Media ID on success.
Video specifications
| Spec | Requirement |
|---|---|
| Format | MP4 or MOV. No edit lists, moov atom at the front of the file |
| Video codec | H.264 or HEVC, progressive scan, closed GOP, 4:2:0 chroma subsampling |
| Audio codec | AAC, 48 kHz max sample rate, mono or stereo |
| Frame rate | 23–60 FPS |
| Aspect ratio | 9:16 required for Reels tab eligibility |
| Duration | 5–90 seconds for Reels tab eligibility |
| Max file size | 100 MB |
The API technically accepts videos up to 15 minutes, but only videos between 5 and 90 seconds with a 9:16 aspect ratio are eligible to appear in the Reels tab. Anything outside that range publishes as a regular video post instead.
The native Instagram app now supports Reels up to 3 minutes (and longer for some accounts), but the Graph API has not caught up. If your workflow generates videos longer than 90 seconds, they cannot be published as Reels through the API.
Cover image handling
You have three options for the Reel’s cover/thumbnail:
Option 1 — Custom cover image (cover_url):
Provide a URL to an external image. Recommended size is 1080 × 1920 pixels (9:16). If the image does not match 9:16, Instagram crops the middlemost 9:16 rectangle.
The cover displays as a center-cropped 1080 × 1080 square on the profile grid, so the center of your image needs to look good at that crop.
Option 2 — Frame selection (thumb_offset):
Specify a millisecond offset into the video to select a specific frame as the thumbnail. Default is 0 (first frame).
Option 3 — Auto-generated:
If you provide neither cover_url nor thumb_offset, Instagram auto-selects a frame.
If you set both cover_url and thumb_offset, the cover image takes precedence.
Audio limitations
You cannot add Instagram’s music library tracks through the API. No trending sounds, no catalogue music, no sound effects from Instagram’s library. If your Reel needs music, it must be embedded in the video file before upload.
The audio_name parameter lets you name the Reel’s audio, but you can only name it once — either during container creation or afterward from the audio page in the app.
Audio specifications:
- Codec: AAC
- Sample rate: 48 kHz maximum
- Channels: mono or stereo
- Max audio file size: 8 MB
The share_to_feed parameter
This controls whether the Reel appears in the main profile feed in addition to the Reels tab:
share_to_feed=true— Reel appears in both the Reels tab and the main feedshare_to_feed=falseor omitted — Reel appears only in the Reels tab
This is a hint, not a guarantee. Instagram may override this based on the account’s settings.
Trial Reels
Trial Reels are shared only to non-followers initially, letting you test content before committing to your full audience:
{ "media_type": "REELS", "video_url": "https://example.com/video.mp4", "caption": "Testing this format", "trial_params": { "graduation_strategy": "MANUAL" }}graduation_strategy accepts:
MANUAL— you graduate the Reel to your full audience manually in the appSS_PERFORMANCE— Instagram automatically graduates the Reel based on engagement performance
Common errors
| Error | Cause | Fix |
|---|---|---|
400 on media_publish | Container not yet FINISHED | Poll status before publishing |
| Error 2207001 | Server-side upload failure | Retry 1–2 times within 30 seconds to 2 minutes, then create a new container |
| Error 9, subcode 2207042 | Publishing rate limit exceeded | Back off and check content_publishing_limit |
| Format/spec errors | Video does not meet technical requirements | Validate codec, resolution, duration, file size before upload |
| Creator Account error | Instagram Creator account, not Business | Switch the account type to Business |
Meta’s recommendation for upload failures: retry only 1–2 times within 30 seconds to 2 minutes. If it still fails, generate a new media container rather than retrying the same one.
Rate limits
Instagram accounts are limited to 100 API-published posts per rolling 24-hour window. This includes all content types — Reels, images, carousels, stories. Carousels count as a single post.
Check current usage before publishing:
GET /{ig-user-id}/content_publishing_limitThe limit is enforced at the media_publish endpoint, not at container creation. You can create containers freely, but publishing is throttled.
Reels vs. feed videos vs. stories
| Reels | Feed videos | Stories | |
|---|---|---|---|
media_type | REELS | VIDEO | STORIES |
| Duration | 5–90s (Reels tab) | Up to 60 min | Up to 60s |
| Aspect ratio | 9:16 | Flexible | 9:16 |
| Cover image | cover_url / thumb_offset | N/A | N/A |
share_to_feed | Yes | N/A | No |
| Upload host (resumable) | rupload.facebook.com | rupload.facebook.com | graph.facebook.com |
| Carousel support | No | No | No |
The same Reel, through Postproxy
Here is what publishing a Reel looks like through Postproxy:
curl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "3 tips that changed how we approach customer onboarding" }, "profiles": ["instagram"], "media": ["https://example.com/reel.mp4"] }'One request. Postproxy handles the container creation, the resumable upload to rupload.facebook.com, the status polling loop, the publish call, and returns the result.
If you want to publish the same video as a Reel on Instagram, a TikTok, and a YouTube Short simultaneously, add the other profiles:
curl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "3 tips that changed how we approach customer onboarding" }, "profiles": ["instagram", "tiktok", "youtube"], "media": ["https://example.com/reel.mp4"] }'For a comparison of how the three short-form video platforms differ, see Instagram Reels vs TikTok vs YouTube Shorts: publishing via API.
What Postproxy handles
Postproxy manages the Reels-specific complexity so your system does not have to:
- Meta app review and approved permissions
- Instagram Business account token exchange and refresh
- Container creation with correct
media_typeand video parameters - Resumable video uploads via
rupload.facebook.com - Status polling loop until
FINISHED - Cover image and
share_to_feedconfiguration - Rate limit monitoring via
content_publishing_limit - Per-platform error reporting with actionable failure reasons
Your system sends a video. Postproxy publishes it as a Reel.
Connect your Instagram account and start publishing through the Postproxy API.
Postproxy
One API for every social platform
Publish to Instagram, X, LinkedIn, TikTok, YouTube and more with a single request. Free plan, no credit card required.