Instagram Reels API: Publish Reels with the Graph API
To publish a Reel through the Instagram API, create a container with media_type=REELS and a public video_url, poll its status_code until it reads FINISHED, then call media_publish. Reels can run 3 seconds to 15 minutes, MP4 or MOV, up to 300 MB. Adeli publishes Reels to Instagram from the same endpoint as every other network.
To publish a Reel with the Instagram Reels API, you make three calls: create a container with media_type=REELS and a public video_url, poll the container's status_code until it reads FINISHED, then call media_publish. A Reel can be 3 seconds to 15 minutes long, MP4 or MOV, up to 300 MB. Older tutorials still quote a 60- or 90-second cap. That limit is gone.
There's no separate Reels API. Reels go through the content publishing flow of the Instagram API, the same one that handles images, Stories, and carousels. Our guide to posting to Instagram via API covers all four formats. This one stays on Reels: the full video spec, the Reels-only parameters, and what each upload error means.
What do you need before you start?
You need a professional Instagram account, an access token with the publishing permission, and a video hosted at a public URL. Personal accounts can't publish through the API. Here's what each login needs, per Meta's content publishing guide:
| Instagram Login | Facebook Login | |
|---|---|---|
| Host | graph.instagram.com |
graph.facebook.com |
| Token | Instagram User access token | Facebook Page access token |
| Permissions | instagram_business_basic, instagram_business_content_publish |
instagram_basic, instagram_content_publish, pages_read_engagement |
| Local file upload | No, public URL only | Yes, with resumable upload |
Meta fetches the video from your server, so the URL has to be publicly reachable when you create the container. If your app publishes for accounts you don't own, you'll also need Advanced Access, which means App Review. Our post on Instagram API permissions explains each scope, and the access token guide covers getting a token and keeping it alive.
What are the Instagram Reels API video requirements?
MP4 or MOV, H.264 or HEVC, 3 seconds to 15 minutes, 300 MB at most. The full spec is in Meta's IG User media reference:
| Spec | Requirement |
|---|---|
| Container | MOV or MP4, moov atom at the front of the file, no edit lists |
| Video codec | HEVC or H.264, progressive scan, closed GOP, 4:2:0 chroma subsampling |
| Audio codec | AAC, 48 kHz maximum sample rate, mono or stereo, 128 kbps |
| Frame rate | 23 to 60 FPS |
| Width | 1920 pixels maximum |
| Aspect ratio | 0.01:1 to 10:1, with 9:16 recommended |
| Video bitrate | VBR, 25 Mbps maximum |
| Duration | 3 seconds to 15 minutes |
| File size | 300 MB maximum |
| Cover image | JPEG, 8 MB maximum, sRGB, 9:16 recommended |
| Caption | 2,200 characters, 30 hashtags, 20 @ tags |
Check where your encoder puts the moov atom. Many encoders write it at the end of the file, and Meta rejects that. With ffmpeg, the -movflags +faststart flag moves it to the front.
Step 1: Create a Reels container
POST to /<IG_ID>/media with media_type=REELS and your video_url. The response is a container ID, not a published post.
curl -X POST "https://graph.instagram.com/v25.0/<IG_ID>/media" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-d '{
"media_type": "REELS",
"video_url": "https://example.com/reel.mp4",
"caption": "Our first Reel through the API",
"share_to_feed": true
}'{ "id": "<IG_CONTAINER_ID>" }With Facebook Login, the call is the same against graph.facebook.com with a Page access token.
Step 2: Check the upload status
GET the container's status_code and wait for FINISHED. Video has to process on Meta's side, and publishing before it's done fails with error 2207027. Meta suggests checking about once a minute, for no more than about 5 minutes.
curl "https://graph.instagram.com/v25.0/<IG_CONTAINER_ID>?fields=status_code" \
-H "Authorization: Bearer <ACCESS_TOKEN>"status_code |
Meaning | What to do |
|---|---|---|
IN_PROGRESS |
Still processing | Wait and check again |
FINISHED |
Ready to publish | Go to Step 3 |
ERROR |
Processing failed | Check the video against the spec, then create a new container |
EXPIRED |
Not published within 24 hours | Create a new container |
PUBLISHED |
Already live | Nothing; don't publish twice |
Step 3: Publish the Reel
POST the container ID to /<IG_ID>/media_publish as creation_id. The response is the Instagram Media ID of the live Reel.
curl -X POST "https://graph.instagram.com/v25.0/<IG_ID>/media_publish" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-d '{"creation_id": "<IG_CONTAINER_ID>"}'If this call times out and you get no media ID back, check the container's status before you retry. PUBLISHED means the Reel is already live, so don't publish it again.
A published Reel reads back as media_type: VIDEO. Request media_product_type to confirm it's a Reel.
How to set a cover, share to feed, and add collaborators
Add these parameters to the container request in Step 1. They're all documented in the IG User media reference:
cover_url. A public URL to a JPEG cover for the Reels tab. If you send bothcover_urlandthumb_offset, Meta usescover_url.thumb_offset. The frame to use as the thumbnail, in milliseconds from the start. It defaults to0, and an offset past the end of the video fails with error 2207057.share_to_feed.truelets the Reel appear in both the Feed and Reels tabs, andfalsekeeps it to the Reels tab. Meta notes that neither value guarantees the Reel shows in the Reels tab.collaborators. Up to 3 Instagram usernames to invite as collaborators.audio_name. A name for the Reel's audio. It can be renamed only once.
Plan the cover for two crops. Meta uses the middle 9:16 rectangle of your cover for the Reels tab and the middle 1:1 square when the Reel is shared to the feed. Keep faces and text in the center so both crops work.
Can I post trial Reels through the API?
Yes. Trial Reels are shown only to people who don't follow the account. Add trial_params with a graduation_strategy to the container request:
{
"media_type": "REELS",
"video_url": "https://example.com/reel.mp4",
"trial_params": { "graduation_strategy": "MANUAL" }
}MANUAL. The account graduates the trial Reel to followers by hand, in the Instagram app.SS_PERFORMANCE. The Reel graduates automatically if it performs well.
trial_params only works with media_type=REELS. Source: the content publishing guide and the media reference.
Why did my Reel upload fail?
Most failed Reels have a file that doesn't match the spec, or were published before processing finished. These are the subcodes you'll see most, from Meta's error code reference:
| Code / subcode | Meta's message (short) | Usual cause and fix |
|---|---|---|
| 352 / 2207026 | Video format is not supported | Re-encode as MP4 or MOV to the spec above, with the moov atom at the front. |
| 9007 / 2207027 | Media is not ready for publishing | You published before FINISHED. Poll the status first. |
| 9 / 2207042 | Reached maximum number of posts | The account hit its 24-hour publishing limit. Retry later. |
| 9004 / 2207052 | Media could not be fetched from this URI | The URL isn't public or has expired. Host the file where Meta can reach it. |
| -2 / 2207003 | Takes too long to download the media | The download timed out. Retry, or host the file somewhere faster. |
| -1 / 2207053 | Unknown upload error | Mostly affects video. Create a new container and retry. |
| 1 / 2207057 | Thumbnail offset out of range | thumb_offset is past the video's length. Use a valid offset in milliseconds. |
| 24 / 2207008 | Media builder does not exist or has expired | Retry once or twice, 30 seconds to 2 minutes apart, then create a new container. |
How many Reels can I post per day?
100 API-published posts per account in a moving 24-hour window, per Meta's content publishing guide. Reels count toward that total along with every other format. Meta's docs conflict on the number: the same guide's carousel section says 50, and the content_publishing_limit reference shows a quota_total of 50 in its example.
Don't hardcode either number. Ask the account:
curl "https://graph.instagram.com/v25.0/<IG_ID>/content_publishing_limit?fields=quota_usage,config" \
-H "Authorization: Bearer <ACCESS_TOKEN>"quota_usage is the number of posts published in the window, and config.quota_total is the cap. The Instagram API rate limit guide covers call limits, which are a separate budget.
Is there a faster way to publish Reels?
Yes, if you'd rather not own the container calls, the polling loop, and token refresh. Adeli publishes feed posts, Reels, Stories, and carousels to Instagram from the same endpoint as every other network. Adeli holds the Meta developer app, carried Meta's review, and refreshes every connected account's tokens, so you hold one API key.
Every publish returns a per-platform status, and a webhook fires when anything changes. The posting API page shows the request shape, and the Instagram publishing reference has the fields. Your first 3 connected accounts are free, with no per-post fees on Instagram.