# Instagram Reels API: How to Publish with Meta (2026)

Dean Fankhauser, Founder · Published 26 Sept 2026 · Learning

_A developer's guide to the Instagram Reels API: choose the right login path, create and check a video container, confirm publication, and handle failures._

## The short answer

- Meta offers two Instagram login configurations with different hosts and permissions.
- For a Reel, create a container, wait for FINISHED, then call media\_publish.
- A container ID proves preparation, not that a Reel is public.
- Postdom's managed workflow covers finished Reels, approvals, scheduling and destination results.

The Instagram Reels API is part of Meta's official content-publishing platform for eligible Instagram professional accounts. To publish a Reel, choose the correct login path and publishing scope, create a media container, poll until it is `FINISHED`, then call `media_publish` and verify the returned media ID. This guide shows those steps, the failure cases that matter in production, and where Postdom's narrower managed Reel workflow fits. It was checked against [Meta's Instagram Platform documentation](https://developers.facebook.com/documentation/instagram-platform/content-publishing/) and [Meta's official Instagram API collection](https://www.postman.com/meta/workspace/instagram/documentation/23987686-9386f468-7714-490f-9bfc-9442db5c8f00) on 27 September 2026.

> **Build the workflow around the result**
>
> If you need a finished Reel to pass through human approval, scheduling and per-account outcome tracking, connect an eligible account. The released Postdom MCP helper sets AI disclosure to true and has no per-call private-visibility option; use it only when those settings fit your Reel. Keep reading to decide whether the native Meta API is the better fit.
>
> [Create a Postdom workspace](https://app.postdom.com/signup)

## Instagram Reels API: three stages from video to published media

The native flow has three operational stages; the middle stage may require multiple status calls. The first stage returns a container ID. It is not a published media ID. The final publish call returns a media ID after the container is ready. Save both IDs and the account ID for reconciliation.

_Instagram Reels API sequence; Meta's container status is the gate between preparation and publication._

| Stage | Native request | Evidence to keep |
| --- | --- | --- |
| Create | \`POST /{ig-user-id}/media\` with \`media\_type=REELS\` and an accessible \`video\_url\` | Container ID and the exact reviewed media/caption |
| Check | \`GET /{container-id}?fields=status\_code,status\` | \`FINISHED\`, \`IN\_PROGRESS\` or a terminal error |
| Publish | \`POST /{ig-user-id}/media\_publish\` with \`creation\_id\` | Returned media ID; then read the media record or permalink |

Meta's [Reels publishing collection](https://www.postman.com/meta/instagram/documentation/6yqw8pt/instagram-api?entity=request-23987686-6fa9ed1d-3310-4844-ad25-f0001ab66f11) shows these requests with the Facebook Login host. Do not send the publish call immediately after creating a video container: media processing is asynchronous. A successful create response only says Meta accepted the container request.

### A minimal native Reel request

The following example illustrates the Facebook Login configuration. Replace the API version with a currently supported version from your Meta app, and use the Page token, Instagram professional account ID and public video URL returned by your own connection flow. Do not copy these placeholders into production.

_Instagram Graph API example for the Facebook Login path; the token and video URL are placeholders._

```bash
# 1. Create a Reel container; save the returned id as CONTAINER_ID.
curl -X POST "https://graph.facebook.com/v{version}/{ig-user-id}/media" \
  -H "Authorization: Bearer {page-access-token}" \
  --data-urlencode "media_type=REELS" \
  --data-urlencode "video_url=https://media.example.com/reviewed-reel.mp4" \
  --data-urlencode "caption=The reviewed caption" \
  --data-urlencode "share_to_feed=false"

# 2. Check the same container until status_code is FINISHED.
curl "https://graph.facebook.com/v{version}/{container-id}?fields=status_code,status" \
  -H "Authorization: Bearer {page-access-token}"

# 3. Only after FINISHED, publish once; save the returned media id.
curl -X POST "https://graph.facebook.com/v{version}/{ig-user-id}/media_publish" \
  -H "Authorization: Bearer {page-access-token}" \
  --data-urlencode "creation_id={container-id}"
```

Host the video where Meta can retrieve it when processing starts. A local file path, localhost URL or expired signed URL will not do. Meta's [official Reels request](https://www.postman.com/meta/instagram/request/gabnx7r/publish-reel) documents `creation_id` on `media_publish`; its [collection](https://www.postman.com/meta/workspace/instagram/documentation/23987686-9386f468-7714-490f-9bfc-9442db5c8f00) documents public video retrieval and checking `status_code` first.

### Reel-specific options in this request

In [Meta's Reel container example](https://www.postman.com/meta/instagram/request/5kkpkh6/upload-a-reel-to-an-ig-container), `share_to_feed=false` places the Reel in the Reels tab, while `true` requests both Feed and Reels placement. Decide that before creating the container; do not treat it as a setting Postdom's released MCP helper exposes per call. Cover and other creative controls depend on the exact Meta publishing surface and API version, so check the current Meta parameters if your product requires them rather than assuming this minimal example sets them.

### What counts as published?

Keep a state machine in your application: `container_created` → `processing` → `ready` → `publish_requested` → `published` or `failed`. `FINISHED` means the video container is ready for the publish call; it does not mean the post is already live. After `media_publish` returns a media ID, read that media record and its permalink if your UI needs a public link. Store the provider response and any error. A timeout is inconclusive; check the original attempt before creating another container or sending another publish request.

A ready status response contains the same container ID and `status_code: "FINISHED"`. Record that response with the publish request and returned media ID. If the publish response is lost, first check whether a media ID or webhook was recorded by your integration; then inspect the professional account's recent media for the exact asset, caption and time window before deciding whether another publish attempt is safe. Meta's container status alone cannot prove that the final `media_publish` call succeeded. Escalate an ambiguous attempt rather than creating a likely duplicate automatically.

## Choose Instagram Login or Facebook Login first

Both Meta configurations target Instagram Business or Creator accounts. They use different authorization paths, hosts and scope names. Mixing them is an easy way to get a token that exists but cannot publish.

_Login requirements from Meta's Instagram API documentation; verify the exact permissions for your app's configuration._

| Decision | Instagram API with Instagram Login | Instagram API with Facebook Login |
| --- | --- | --- |
| Linked Facebook Page | Not required | Required for the professional account |
| Publishing scope | \`instagram\_business\_content\_publish\` | \`instagram\_content\_publish\` |
| Profile scope | \`instagram\_business\_basic\` | \`instagram\_basic\` |
| Typical API host | \`graph.instagram.com\` | \`graph.facebook.com\` |
| Token path | Instagram user authorization | Facebook and Page authorization |

Meta's [official collection](https://www.postman.com/meta/workspace/instagram/documentation/23987686-9386f468-7714-490f-9bfc-9442db5c8f00) explicitly says Instagram Login does not need a linked Facebook Page and lists its `instagram_business_*` scope values. Its Facebook Login section describes the linked Page and `instagram_content_publish`. Choose the configuration before copying an example request; a `graph.facebook.com` example with a Page access token is not a drop-in template for Instagram Login.

For the Instagram Login route, start with [Meta's Instagram Login collection](https://www.postman.com/meta/instagram/folder/1z5vxzu/instagram-api-with-instagram-login) for its scopes and account prerequisites, then use the current Instagram Login content-publishing documentation in your Meta app for the matching token and request host. The runnable Reel example above comes from Meta's Facebook Login collection; it is deliberately not presented as an Instagram Login request.

The short implementation checklist is: **professional account → login configuration → matching token and publishing scope → public video URL → container ID → \`FINISHED\` → \`media\_publish\` → returned media ID**. Store the account, source URL and caption alongside those IDs. This is the answer to “can my app post this Reel?” more reliably than checking whether an access token exists.

For an app serving other people's accounts, also plan for Meta's access-level and app-review requirements. A development role or test account working in your app is not evidence that arbitrary customer accounts are authorized. Verify the current [Meta app-review requirements](https://developers.facebook.com/documentation/instagram-platform/app-review) for the permissions and use case you actually request.

## Validate the Reel and the account before you queue it

Check that the connected account is an eligible professional account, the user granted the publishing permission for the chosen login path, the access token is usable, and the media URL remains publicly retrievable. Validate the video against Meta's \*current\* Reels requirements rather than a number copied from a provider blog. Meta's [official Reels collection](https://www.postman.com/meta/workspace/instagram/documentation/23987686-9386f468-7714-490f-9bfc-9442db5c8f00) listed the following for its example when checked on 27 September 2026; recheck the current collection for your API version before enforcing them.

_Meta's published Reel media requirements in its official API collection, checked 27 September 2026._

| Property | Documented value |
| --- | --- |
| Container | MOV or MP4 |
| Video and audio | H.264 or HEVC video; AAC audio |
| Frame rate and shape | 23–60 FPS; 9:16 recommended |
| Duration and file size | 3 seconds to 15 minutes; up to 1 GB |

These are accepted-media requirements in that documentation, not a promise of Reels-tab distribution or a guarantee that a particular account can post every file at the upper bound. Inspect the real asset and account before queueing it.

An application also needs to decide who may approve a caption or scheduled time. Meta's publishing endpoint does not provide your team's review record, queue or business rules. If a human changes the caption after approving the video, review that final version before submission. Keep the selected Instagram account, media URL, caption and scheduled instant together as one logical request.

### Limits and failures to handle explicitly

Meta publishes separate controls for content publishing and broader API usage. Check the current account's `content_publishing_limit` and the response headers and errors for your app. Avoid hardcoding a competitor's claimed hourly request count or daily post ceiling as a universal guarantee. Limits and eligibility can differ by API configuration, account and version.

- **Container still processing:** keep the original container ID and poll with a bounded backoff. Publish only after `FINISHED`.
- **Container failed or URL inaccessible:** fix the asset, then create a new container deliberately. Preserve the original error for diagnosis.
- **Permission or account failure:** confirm the login path, account type, linked Page when applicable, granted scopes and app access level.
- **Rate limit response:** pause and use Meta's returned information. A faster retry loop will not make publication happen sooner.
- **Publish response lost:** reconcile the original media/container IDs before retrying so a network timeout does not create duplicate posts.

## Build directly or use Postdom?

Build directly against Meta when you need Instagram-specific publishing controls, feed images, carousels, Stories, or other Graph API features beyond finished Reels. You will own authorization, media hosting, container processing, retries, queueing, approval logic and result tracking.

Use [Postdom's Instagram posting API workflow](https://postdom.com/platforms/instagram-reels/instagram-posting-api) when your job is to send a supplied, finished Reel through a connected workspace with an exact UTC schedule, a stable idempotency key and a readable destination outcome. Human approval is controlled by the workspace's policy; configure per-post review if that is the required gate. The current [released MCP helper](https://postdom.com/for/social-media-mcp) exposes `list_accounts`, `publish_video` and `get_publish` for that workflow. It does not turn this Reel path into a general Instagram Graph API proxy for feed photos, carousels, Stories, comments or ads.

_Scope and ownership comparison for teams choosing a publishing integration._

| Task | Native Meta integration | Postdom Reel workflow |
| --- | --- | --- |
| Connect an account | Build and maintain the chosen Meta login and token flow | A human connects an eligible account to a workspace |
| Prepare media | Host the video and create a native container | Supply a finished video URL or supported stored media handle |
| Approval and schedule | Build the review record and queue yourself | Use workspace approval and a reviewed UTC \`publish\_at\` |
| Retry identity | Preserve native IDs and reconcile original attempts | Reuse a stable idempotency key; read the saved Postdom post ID |
| Publication evidence | Store Meta's media ID and retrieve the media record | Read the Instagram destination state and public URL when available |
| Other Instagram formats | Use the relevant native endpoints and requirements | Not promised by the Reel workflow described here |

> **Try the managed Reel path**
>
> Connect one eligible Instagram account and test a human-reviewed Reel. Check the product boundary below before you build against the API.
>
> [Start free with Postdom](https://app.postdom.com/signup)

![Postdom review screen with a request-changes dialog before a social post is approved](https://cdn.sanity.io/images/tz7vebuf/production/d980f882c50f5d67b9b22ef93b2aa5347a864b48-1440x900.png?w=1200&auto=format)

_Instagram Reels API workflow: the Postdom approval screen can request changes before a queued social post; illustrative workspace data, not an Instagram publication._

### The Postdom request and result

Copy the `providerAccountId` from `list_accounts()`. Submit the reviewed video and caption once, save the returned Postdom post ID, then read that same ID with `get_publish()`. `requires_approval`, `scheduled` and `publishing` are intermediate states. A successful submission response is not a claim that Instagram has published the Reel. See the [publish tool reference](https://postdom.com/docs/tools/publish-video) and [Instagram destination defaults](https://postdom.com/docs/destinations/instagram-reels) for the current contract.

The released `@postdom/mcp@0.4.0` helper fixes Instagram settings to `contentType: "reel"` and `isAiGenerated: true`. It has no per-call Instagram AI-disclosure override or private-visibility input. Confirm that the video really is AI-generated and that the connected account's audience is appropriate **before** authorizing this path. If the disclosure would be false, stop and use a suitable publishing method. A `true` field is an assertion sent by the helper, not proof that a person reviewed the content.

_Illustrative Postdom MCP sequence; replace each placeholder with values from your workspace._

```
1. list_accounts({})
   Copy the connected Instagram account's providerAccountId.

2. publish_video({
     account_ids: ["<providerAccountId>"],
     video_url: "https://your-host.example/reviewed-reel.mp4",
     caption: "<approved caption>",
     intent: "Publish the reviewed Instagram Reel",
     publish_at: "<reviewed future UTC instant>",
     idempotency_key: "<stable key for this unchanged post>"
   })
   Save the returned Postdom post ID.

3. get_publish({ post_id: "<returned Postdom post ID>" })
   Read the Instagram destination outcome; do not infer it from step 2.
```

The request above is illustrative. The URL is not a real video; no live Instagram publication is claimed. A human should review the actual account, media, caption and scheduled time. For an agent-run workflow, read [how Postdom handles Instagram automation](https://postdom.com/for/instagram-automation).

## FAQ

**Can a personal Instagram account use the posting API?**

No. The Meta publishing configurations covered here target eligible Business or Creator professional accounts. Convert or connect the right account before building a publish flow.

**Do I need a linked Facebook Page?**

For Instagram API with Instagram Login, Meta says no linked Page is required. For Instagram API with Facebook Login, the professional Instagram account must be linked to a Page. The hosts, tokens and scope names differ too.

**Can I post an Instagram Reel in one Meta API call?**

Not with the native container sequence shown here. Create the Reel container, wait for \`FINISHED\`, then call \`media\_publish\`. A managed service may offer one application-facing submission while it handles the native sequence.

**Does a container ID mean my Reel is published?**

No. It identifies a preparation attempt. Wait for readiness, publish the container, then use the returned media ID and provider result for your publication record.

**Can Postdom publish photos, carousels or Stories through this workflow?**

This guide covers supplied, finished Reels. The released workflow described here does not promise those other formats or arbitrary Instagram Graph API calls. Use Meta's appropriate native surface when you need them.

**Can Meta's native API publish Instagram photos or carousels?**

Yes, for eligible professional accounts and with the correct publishing permissions. Images use a media container and publish call; a carousel also needs its child containers and a parent container. This article's request example is specifically for \`media\_type=REELS\`, so do not reuse its parameters as a photo or carousel recipe. Use Meta's content-publishing documentation for those formats.

**What should I do if a publish request times out?**

Keep the original container ID or Postdom post ID and reconcile its state. Do not assume nothing happened and submit a second post immediately. Make a new attempt only after you know the original outcome.

---

Canonical: https://postdom.com/blog/instagram-reels-api
