# Instagram Stories API: Publish Stories and Read Insights

How to publish Instagram Stories through the Graph API with media_type=STORIES: specs, account types, mentions, what stickers can't do, and Story insights.

Canonical page: https://www.tryadeli.com/blog/instagram-stories-api
Last updated: 2026-11-02

By Nick Reyes, Co-founder and CTO, Adeli. Published 2026-11-02.

## The short answer

The Instagram Stories API is the content publishing flow with media_type=STORIES: create a container from a public JPEG or video URL, wait for video to finish processing, then call media_publish. Stories take no stickers or captions, video runs 3 to 60 seconds, and Story insights vanish after 24 hours. Adeli publishes image and video Stories through one API.

The Instagram Stories API is Meta's content publishing flow with **`media_type=STORIES`**: you create a container from a public image or video URL, wait for the video to process, then publish it with `media_publish`. A Story goes live for 24 hours, and its insights disappear on the same clock.

Most of the trouble comes from what the API won't do. Developers keep finding out that **stickers, links, and polls can't be added**, that Creator accounts hit walls, and that Story metrics expire before a daily report job gets to them. This guide covers the publishing calls, the spec, which accounts can post, mentions, and Story insights. Our guide to [posting to Instagram via API](https://www.tryadeli.com/blog/post-to-instagram-via-api) compares all four formats side by side, and the [Instagram Reels API](https://www.tryadeli.com/blog/instagram-reels-api) post covers Reels.

## What do you need to publish an Instagram Story through the API?

**Publishing an Instagram Story needs a professional Instagram account, a token with the content publishing permission, and the media at a public URL** (or uploaded through Meta's resumable upload). Meta's [content publishing guide](https://developers.facebook.com/docs/instagram-platform/content-publishing) lists three setups:

| | Instagram Login | Facebook Login | Unified Login |
|---|---|---|---|
| **Host** | `graph.instagram.com` | `graph.facebook.com` | `graph.facebook.com` |
| **Token** | Instagram User access token | Facebook Page access token | Business Integration System User access token |
| **Permissions** | `instagram_business_basic`, `instagram_business_content_publish` | `instagram_basic`, `instagram_content_publish`, `pages_read_engagement` | `instagram_basic`, `instagram_content_publish` |
| **Resumable file upload** | No | Yes | Yes |

**Use a Business account if you can.** Meta opened the Content Publishing API to Creator accounts in [June 2023](https://developers.facebook.com/blog/post/2023/06/12/introducing-new-features-and-expanded-user-types-to-the-instagram-content-publishing-api/), a month after Stories arrived. But developers on Meta's forum report that **Story containers fail for Creator accounts** while Reels and images from the same account work. The current reference doesn't state a rule either way. If your users include creators, run a Story through a Creator account in testing before you promise the feature.

Publishing for accounts you don't own also needs Advanced Access, which means Meta app review. The [Instagram API permissions](https://www.tryadeli.com/blog/instagram-api-permissions) guide explains each scope.

## What are the Instagram Story specs?

**Instagram Story images must be JPEG up to 8 MB, and Story videos must be MP4 or MOV, 3 to 60 seconds, up to 100 MB.** Meta recommends 9:16 for both. The full spec comes from the [IG User media reference](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media):

| Spec | Image Story | Video Story |
|---|---|---|
| **Format** | JPEG only | MP4 or MOV with the moov atom first and no edit lists |
| **File size** | 8 MB maximum | 100 MB maximum |
| **Duration** | — | 3 to 60 seconds |
| **Aspect ratio** | 9:16 recommended | 0.1:1 to 10:1 allowed, 9:16 recommended |
| **Codecs** | sRGB (other color spaces get converted) | HEVC or H.264, AAC audio at 48 kHz max, 128 kbps |
| **Frame rate and width** | — | 23 to 60 FPS, 1,920 pixels wide at most |
| **Bitrate** | — | VBR, 25 Mbps maximum |

Two limits are tighter than the feed: **a Story video caps at 60 seconds, where a Reel can run 15 minutes**, and at 100 MB, a third of the Reels ceiling. Trim long clips before you create the container, because Meta rejects the file rather than cutting it.

## Step 1: Create a Story container

**POST to `/<IG_ID>/media` with `media_type=STORIES` and either `image_url` or `video_url`.** This is the "Instagram API for posting stories" call. It returns a container ID, not a live Story.

```bash
curl -X POST "https://graph.facebook.com/v26.0/<IG_ID>/media" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -d '{
    "media_type": "STORIES",
    "video_url": "https://example.com/story.mp4"
  }'
```

```json
{ "id": "<IG_CONTAINER_ID>" }
```

For an image Story, swap `video_url` for `image_url` with a JPEG. With Instagram Login, call `graph.instagram.com` with an Instagram User access token instead.

## Step 2: Wait for the video to finish processing

**For a video Story, GET the container's `status_code` until it reads `FINISHED`.** Meta's guide suggests checking once a minute for no more than 5 minutes.

```bash
curl "https://graph.facebook.com/v26.0/<IG_CONTAINER_ID>?fields=status_code" \
  -H "Authorization: Bearer <ACCESS_TOKEN>"
```

`ERROR` means the file broke the spec. `EXPIRED` means nobody published the container within 24 hours, so create a new one. The [Reels guide](https://www.tryadeli.com/blog/instagram-reels-api) has the full status table and the upload error subcodes, which are the same for Stories.

## Step 3: Publish the Story

**POST the container ID to `/<IG_ID>/media_publish` as `creation_id`.** The response holds the Instagram Media ID of the live Story.

```bash
curl -X POST "https://graph.facebook.com/v26.0/<IG_ID>/media_publish" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -d '{"creation_id": "<IG_CONTAINER_ID>"}'
```

**Save that media ID right away.** You need it for Story insights, and Meta stops serving the Story after 24 hours. When you read it back, `media_product_type` returns `STORY`, while `media_type` only says `IMAGE` or `VIDEO`.

## Can I upload a Story file instead of a URL?

**Yes, with Facebook Login or Unified Login, through Meta's resumable upload on `rupload.facebook.com`.** Create the container with `upload_type=resumable`, then send the file's bytes to the upload URL Meta returns. Meta's publishing guide says every media type shares that same video upload flow, Stories included.

With Instagram Login, there is no upload endpoint. **Host the file somewhere Meta can fetch it**, such as a short-lived signed URL from your storage bucket, and pass it as `video_url` or `image_url`. Meta has to reach the file when you create the container, so a link that expires in seconds fails.

## Can I add stickers, links, or mentions to a Story?

**The Instagram API publishes mentions on Stories but not stickers.** Meta's [IG User media reference](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media) says publishing **link, poll, and location stickers is not supported**. Here's what a Story container accepts:

| Feature | Through the API? | Notes |
|---|---|---|
| **Link sticker** | No | No API field adds a link to a Story |
| **Poll, quiz, question stickers** | No | Add them in the Instagram app instead |
| **Location sticker** | No | Covered by the same sticker restriction |
| **Mentions** | Yes | `user_tags` with a `username`; `x` and `y` are optional on Stories (added July 2025) |
| **Collaborators** | No | Meta marks `collaborators` as not supported for Stories |
| **Alt text** | No | `alt_text` excludes Reels and Stories |
| **Shopping tags and filters** | No | Not supported on any API-published media |

A mention looks like this. Include coordinates only if you want to place the tag:

```json
{
  "media_type": "STORIES",
  "image_url": "https://example.com/story.jpg",
  "user_tags": [{ "username": "partneraccount", "x": 0.5, "y": 0.8 }]
}
```

**If your product needs a swipe-up link, put it somewhere the API can reach**: the caption of a feed post or Reel, or the account's bio. A Story can't carry it.

## Common mistakes with the Instagram Stories API

Most failed Stories in developer threads come from three things: **features the API doesn't publish, the account type, and old forum answers** that predate Meta's changes.

> Posting a story via graph.instagram.com works fine - but as soon as I add the parameter "user_tags" **I get an error**

— [Eric on the Meta Developer Community](https://developers.facebook.com/community/threads/462087226319957/)

> same problem, **i cannot manage to add any info (location, user tags...) on story, only a plain photo.**

— [Grégoire on the Meta Developer Community](https://developers.facebook.com/community/threads/462087226319957/)

> Old but in the actual documentation facebook is expliciting that's **only available for business accounts**

— [Manoel, answering a Creator account Stories question on the Meta Developer Community](https://developers.facebook.com/community/threads/1226500261819047/)

Those threads predate the July 2025 change that made Story mentions work, so **tagging a username is fine now; location still isn't.** The account type issue hasn't gone away: test Creator accounts before you rely on them, as covered in the [prerequisites](#what-do-you-need-to-publish-an-instagram-story-through-the-api) above.

## How do I list an account's live Stories?

**Call `GET /<IG_ID>/stories` on an account that authorized your app.** The [stories edge reference](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/stories) returns the Story media IDs that are still live. The regular `/media` edge leaves Stories out.

```bash
curl -G "https://graph.facebook.com/v26.0/<IG_ID>/stories" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  --data-urlencode "fields=id,media_type,media_product_type,timestamp,permalink"
```

The edge has gaps worth knowing:

- **No Live Video Stories.** Meta leaves them out of the response.
- **No reshared Stories.** A Story the account created by resharing another Story isn't returned.
- **No updates or deletes** through this edge. It only reads.
- **No other accounts.** You can only read Stories for accounts that authorized your app. Business discovery, the endpoint for reading other accounts, has no Stories field; see our [Instagram business discovery API](https://www.tryadeli.com/blog/instagram-business-discovery-api) guide for what it does return.

## How does the Instagram story insights API work?

**The Instagram story insights API is the media insights endpoint, `GET /<IG_MEDIA_ID>/insights`, called with a Story's media ID within 24 hours of posting.** It needs `instagram_manage_insights` (or `instagram_business_manage_insights` with Instagram Login). Our [Instagram insights API](https://www.tryadeli.com/blog/instagram-insights-api) guide covers account metrics and feed posts; this section stays on Stories.

```bash
curl -G "https://graph.facebook.com/v26.0/<IG_MEDIA_ID>/insights" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  --data-urlencode "metric=views,reach,replies,shares,link_clicks"
```

The `navigation` metric counts every action taken from the Story. Request it on its own with the `story_navigation_action_type` breakdown, which Meta says works only with `navigation`:

```bash
curl -G "https://graph.facebook.com/v26.0/<IG_MEDIA_ID>/insights" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  --data-urlencode "metric=navigation" \
  --data-urlencode "breakdown=story_navigation_action_type"
```

The response splits into the four actions Meta tracks, per the [media insights reference](https://developers.facebook.com/docs/instagram-platform/reference/instagram-media/insights). Added together, they equal the `navigation` total:

| Breakdown value | What the viewer did |
|---|---|
| `TAP_FORWARD` | Tapped to the next frame |
| `TAP_BACK` | Tapped back to the previous frame |
| `TAP_EXIT` | Left the Stories viewer |
| `SWIPE_FORWARD` | Swiped to the next Story |

That breakdown replaced the old `taps_forward`, `taps_back`, and `exits` metrics. **`link_clicks` arrived in June 2026** and counts taps on links in the Story, such as a link sticker added in the app.

Plan for these Story-specific rules:

- **24-hour window.** Story metrics stop being available after 24 hours. A nightly reporting job will miss Stories posted the previous morning.
- **The 5-viewer floor.** A metric with a value under 5 returns error 10, `(#10) Not enough viewers for the media to show insights`. Show it as too small to report.
- **Regional zeros.** Meta says `replies` doesn't include replies from users in some regions, and returns `0` for Stories created in those regions.

### Getting Story insights before they expire

**Subscribe to the `story_insights` webhook field so Meta pushes the numbers to you.** Meta's insights reference recommends it for exactly this reason. Per Meta's [webhook fields table](https://developers.facebook.com/documentation/instagram-platform/webhooks/fields), the field works with Facebook Login and Unified Login, and **not with Instagram Login**. On Instagram Login, poll each live Story's insights on a schedule shorter than 24 hours and store what you get.

## Can the API show who viewed a Story?

**No. The Instagram API returns Story view counts, not the viewers.** The media insights reference documents `views` (how many times the Story played) and `reach` (an estimate of unique accounts that saw it). No endpoint in Meta's references returns the list of accounts that watched a Story, so the closest thing to a story viewers endpoint is **the `reach` count.**

## Is there a faster way to publish Instagram Stories?

**Yes. [Adeli](https://www.tryadeli.com/product/instagram) publishes image and video Stories to Instagram through one API call**, with no Meta developer app, app review, or token refresh job on your side. Adeli connects accounts through Meta's Unified Login and holds the Meta app, so you hold one API key. The request uses the same endpoint as every other network:

```bash
curl -X POST "https://app.tryadeli.com/api/v1/posts" \
  -H "Authorization: Bearer $ADELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "instagram",
    "accountId": "<ADELI_ACCOUNT_ID>",
    "story": {
      "url": "https://media.example.com/story.mp4",
      "userTags": [{ "username": "partneraccount" }]
    }
  }'
```

What Adeli does with a Story, per the [Instagram publishing reference](https://www.tryadeli.com/docs/api/posts/publish-instagram):

- **Checks the spec first.** A video Story must run 3 to 60 seconds, and fields Stories don't take (caption, collaborators, alt text) are rejected with a `400` instead of being silently dropped.
- **Handles the upload.** Stage a local file with [direct uploads](https://www.tryadeli.com/docs/api/posts/create-media-uploads) and Adeli delivers it to Meta, so you don't host public URLs.
- **Reports status.** Staged uploads return `202` with a status URL you poll while Meta processes the video.

Adeli's [analytics API](https://www.tryadeli.com/social-media-analytics-api) reads account-level Instagram insights, which include Story interactions. **Per-Story metrics still come from Meta's insights endpoint** within the 24-hour window. Adeli is free to start with no per-post fees; see [pricing](https://www.tryadeli.com/pricing) for the details.

## Frequently asked questions

### Do Stories count toward the Instagram API daily publishing limit?

Yes. When Meta raised the cap in June 2023, it said the limit applies across all media types, Stories included. Read the account's content_publishing_limit edge to see how much of the 24-hour quota is left before you queue a batch of Stories.

### Can I read another account's Stories through the API?

No. The stories edge only works on an Instagram account that authorized your app, and business discovery, the endpoint for other accounts' public data, has no Stories field. Competitor Stories are out of reach through Meta's official API.

### Does a Story reached through a highlight keep its insights?

Sometimes. Meta says Story metrics are only available for 24 hours, but also that you may receive data after the Story expires if the account added it to a highlight. Don't build on that exception; capture metrics before the 24 hours run out.

## 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.
- [Social Media Analytics API](https://www.tryadeli.com/social-media-analytics-api.md): Adeli's analytics API: Instagram, TikTok, Facebook Page, and YouTube insights endpoints, plus per-post engagement on every post an account has made.
- [All posts on the Adeli blog](https://www.tryadeli.com/blog.md)

## About the author

Nick Reyes is the CTO behind Adeli and builds its API, its platform integrations, and the docs. He is a product engineer with 10 years of experience at Phantom, Airbnb, and Google.
