Stories and highlights
The media inside a story reel or a highlight.
Both endpoints return the media items of one reel, as a single page —
has_more is always false and next_cursor is null.
A user's active stories
GET /stories/{reel_id} takes the story owner's user id, not an
individual story's id. It is an alias for
GET /users/{id}/stories served through
a different Instagram endpoint.
There is no fetch-one-story-by-its-own-id endpoint. If you are migrating from
a provider that had one, fetch the owner's reel and match on the item's pk.
What comes back
The standard list envelope, with story media items — see the highlight example below, which is the same shape.
A highlight's media
Highlight ids come from
GET /users/{id}/highlights. The bare id
and the highlight: prefixed form both work.
What comes back
Both endpoints return the standard list envelope with media objects in the
same shape as a post, plus the story-specific
fields Instagram adds — expiring_at, and story_* sticker arrays where the
item carries a poll, question, link or mention.
{
"items": [
{
"pk": "3012345678901234567",
"media_type": 2,
"taken_at": 1699999999,
"expiring_at": 1700086399,
"image_versions2": { "candidates": [{ "url": "..." }] },
"video_versions": [{ "width": 720, "height": 1280, "url": "..." }],
"user": { "pk": "25025320", "username": "instagram" }
}
],
"next_cursor": null,
"has_more": false
}Downloading the media
There is no download endpoint, and none is needed: every item carries its
file URLs in image_versions2 and video_versions. Fetch the highest-quality
entry directly.
Those URLs are signed and expire within hours, so download promptly rather than storing the URL.
Starting from a share link
A /s/ link resolves through
GET /oembed?url=, which returns the
reel_id to pass here.
Errors
| Code | When |
|---|---|
not_found | The reel expired, or the id is wrong. |
private_account | The owner is private. |
upstream_error | Transient. Retry. |