Instagram Reels API: Publish Reels with the Graph API

By Mika ReyesPublished 6 min read

The short answer

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 both cover_url and thumb_offset, Meta uses cover_url.
  • thumb_offset. The frame to use as the thumbnail, in milliseconds from the start. It defaults to 0, and an offset past the end of the video fails with error 2207057.
  • share_to_feed. true lets the Reel appear in both the Feed and Reels tabs, and false keeps 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.

faq

Frequently asked questions

Why does my Reel show as VIDEO in the API?

Because Meta returns media_type VIDEO for published Reels. To tell a Reel apart from other video, request the media_product_type field on the media object. The Reel published fine. The Instagram API labels Reels as VIDEO.

Can I upload a local video file instead of a URL?

With Facebook Login for Business, yes. Create the container with upload_type=resumable, then send the file's bytes to rupload.facebook.com. Meta documents resumable upload only for that login. With Instagram Login, host the video at a public URL and pass it as video_url.

Can I schedule Reels through the Instagram API?

Meta's content publishing guide doesn't document a scheduling parameter. You run your own queue and call media_publish when each Reel is due. Create the container close to that time, because a container that isn't published within 24 hours expires.

Power your next project
with one social media API

Give your users publishing, scheduling, and analytics through one integration your team can actually maintain.

Try with agents

Start with free credits. No credit card required.