Read an account’s active stories
The stories a public Instagram account has up right now, oldest first: every frame with its media, posting and expiry time, attached links and re-shared posts, plus the account’s profile. Use it to catch stories before they expire. Pass a username or profile URL.
/user-stories Accounts https://api.fetchlayer.dev/instagram/user-stories Headers
Authorization string required Bearer token — your FetchLayer API key.
Parameters
username string optional A username with or without the @, or a profile URL. Give this or userId.
userId string optional The account’s numeric id (profile.id), as a string of digits. Give this or username. An id names the account even after it changes its username; an id that belongs to no account is a 404. Name the account with exactly one of username and userId; both or neither is a 400.
include string[] optional Optional: ["native"] fills profile.native, the account’s full profile record under Instagram’s own field names (see user-profile). It adds about a second with username, and usually nothing with userId. Any other value is a 400.
format string optional json or markdown, lowercase; any other value is a 400. Over MCP, markdown returns the result rendered as text; the REST API accepts it and returns JSON. (default: json)
timeoutMs integer optional Time limit for the whole request, in milliseconds (1000–120000); a value outside that range is a 400. When it runs out, a paged request returns what it has with nextCursor, billed for the pages it returned; a request with nothing to return yet fails with a 503 you can retry, marked with the response header X-Timeout-Source: caller. Left out, the request runs as long as it needs. A call usually takes 2–5 seconds, under a second when there is no active story, and occasionally up to about 30. Under heavy load it can answer 503; retry after a short wait.
Response Fields
user-stories
Read an account’s active stories
transport string The data source: always the platform id, "instagram".
notes string[] Caveats you can act on — a ceiling Instagram imposes, a counter it withholds, a list that stopped early. Several real limits are reported only here, so read them. An empty result always comes with a note explaining it, never as an unexplained empty array.
pagesFetched number Pages of results fetched, which is what the request costs: one credit per page. resolve-url reports 0 and is not billed.
restricted boolean True for an account Instagram restricts — typically an age-restricted brand such as alcohol or cannabis — and false for every other. Such an account answers 200, not 404, with less detail. Its stories come back the same way as any other account’s.
minimumAge integer | null The minimum age Instagram states for a restricted account, or null when it states none (and on every other account).
username string The account the stories belong to.
profile object The account’s profile in the user-profile shape, including the exact stats.postCount (the same rule as user-profile).
profile.native object | null Only with include ["native"]: the account’s full profile record as Instagram publishes it, field for field under Instagram’s own field names — account_type (1 personal, 2 business, 3 creator), category, public_email, public_phone_number, the address fields, hd_profile_pic_url_info, bio_links with link_id, fbid_v2 and more, around 240 fields. Every id is an exact string; an empty string means the account has not published that detail. Null when not available this time (the note says so, and nativeUnavailableReason says why); absent without the include.
profile.nativeUnavailableReason object | null Only with include ["native"]: null when native is present, otherwise {code, retryable} saying why it is null: time-limit (timeoutMs left too little time; allow more), temporarily-unavailable (asking again usually returns it). Naming the account by userId makes the record faster to get.
latestStoryAt string | null When the account last posted a story (ISO 8601), or null when it has none. With a complete list it equals the newest frame’s takenAt.
stories object[] | null The active frames, oldest first, normally current to the second. Empty when the account has no active story; null for a private account. Each comes with a note, and both are ordinary answers that cost 1 credit, not errors. On rare occasions the very newest frame is not in the list yet: the note says the most recent story may not be included, and a later call picks it up.
stories[].id string Instagram’s exact id for the frame, as a string (a 64-bit number; keep it as a string). A link built from it is exact: https://www.instagram.com/stories/<username>/<id>/.
stories[].url string | null Link to the frame on Instagram.
stories[].kind string image or video.
stories[].takenAt string | null When the frame was posted (ISO 8601).
stories[].expiresAt string | null When Instagram will take the frame down (ISO 8601), normally 24 hours after takenAt.
stories[].width integer | null Pixel width.
stories[].height integer | null Pixel height.
stories[].durationSeconds number | null A video frame’s length in seconds; null for an image.
stories[].hasAudio boolean | null Whether a video frame has sound; null for an image.
stories[].thumbnailUrl string | null Preview image, or null.
stories[].assets object[] Every rendition — video first, then images, largest first — each with kind, url, width, height and a downloadUrl that keeps working after Instagram’s own link expires.
stories[].links object[] Links the account attached to the frame, each with its url, unwrapped to the real destination.
stories[].sharedPosts object[] Posts the account re-shared into the frame, each with its shortcode and url — pass either to post-detail.
storyCount number How many frames are in this response.
Request
curl -X POST "https://api.fetchlayer.dev/instagram/user-stories" \
-H "Authorization: Bearer ss-your-key" \
-H "Content-Type: application/json" \
-d '{"username":"@nasa"}'Response
{
"transport": "instagram",
"notes": [],
"pagesFetched": 1,
"restricted": false,
"minimumAge": null,
"username": "nasa",
"profile": {
"id": "528817151",
"username": "nasa",
"url": "https://www.instagram.com/nasa/",
"fullName": "NASA",
"verified": true,
"privateAccount": false,
"hasActiveStory": true,
"latestStoryAt": "2026-10-12T21:47:37.000Z",
"country": null,
"dateJoined": null,
"stats": {
"followerCount": 104352683,
"followingCount": 91,
"postCount": null
}
},
"latestStoryAt": "2026-10-12T21:47:37.000Z",
"stories": [
{
"id": "4006121587703428119",
"url": "https://www.instagram.com/stories/nasa/4006121587703428119/",
"kind": "video",
"takenAt": "2026-10-12T21:47:37.000Z",
"expiresAt": "2026-10-13T21:47:37.000Z",
"width": 720,
"height": 1280,
"durationSeconds": 14.8,
"hasAudio": true,
"thumbnailUrl": "https://scontent-fra5-1.cdninstagram.com/v/t51.82787-15/...",
"assets": [
{
"kind": "video",
"url": "https://scontent-fra5-1.cdninstagram.com/o1/v/t2/f2/m86/...",
"width": 720,
"height": 1280,
"downloadUrl": "https://api.fetchlayer.dev/instagram/media?url=..."
},
{
"kind": "image",
"url": "https://scontent-fra5-1.cdninstagram.com/v/t51.82787-15/...",
"width": 720,
"height": 1280,
"downloadUrl": "https://api.fetchlayer.dev/instagram/media?url=..."
}
],
"links": [
{
"url": "https://www.nasa.gov/ways-to-watch"
}
],
"sharedPosts": []
}
],
"storyCount": 1
}