# Instagram Reels API: Publish Reels with the Graph API

How to publish Reels with the Instagram Reels API: video specs, the container, status, and publish calls, covers, collaborators, trial Reels, and upload errors.

Canonical page: https://www.tryadeli.com/blog/instagram-reels-api
Last updated: 2026-10-09

By Mika Reyes, Co-founder, Adeli. Published 2026-10-09.

## 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](https://www.tryadeli.com/blog/instagram-api-guide), the same one that handles images, Stories, and carousels. Our guide to [posting to Instagram via API](https://www.tryadeli.com/blog/post-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](https://developers.facebook.com/docs/instagram-platform/content-publishing):

| | 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](https://www.tryadeli.com/blog/instagram-api-permissions) explains each scope, and the [access token guide](https://www.tryadeli.com/blog/instagram-api-access-token) 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](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media):

| 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.

```bash
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
  }'
```

```json
{ "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**.

```bash
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.

```bash
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](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media):

- **`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:

```json
{
  "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](https://developers.facebook.com/docs/instagram-platform/content-publishing) and the [media reference](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media).

## 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](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/error-codes):

| 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](https://developers.facebook.com/docs/instagram-platform/content-publishing). 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](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/content_publishing_limit) shows a `quota_total` of 50 in its example.

Don't hardcode either number. Ask the account:

```bash
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](https://www.tryadeli.com/blog/instagram-api-rate-limit) 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](https://www.tryadeli.com/product/instagram) 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](https://www.tryadeli.com/social-media-posting-api) page shows the request shape, and the [Instagram publishing reference](https://www.tryadeli.com/docs/api/posts/publish-instagram) has the fields. **Your first 3 connected accounts are free**, with no per-post fees on Instagram.

## 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.

## Related Adeli pages

- [Instagram API for Developers](https://www.tryadeli.com/product/instagram.md): Publish, schedule, and read analytics for Instagram through one API. Adeli owns the Instagram developer app, token refresh, and Meta review. Free to start.
- [Social Media Posting & Scheduling API](https://www.tryadeli.com/social-media-posting-api.md): Adeli's social media posting and scheduling API publishes to Instagram, TikTok, YouTube, Facebook, X, and Bluesky in one request, now or at a set time. Free to start.
- [All posts on the Adeli blog](https://www.tryadeli.com/blog.md)

## About the author

Mika Reyes is the CEO behind Adeli and a tech and AI content creator. She was previously co-founder and CEO of Parallax, which was acquired by Phantom, and a product lead at LinkedIn. She is a Forbes 30 Under 30 honoree.
