Instagram Downloader API: Reels, Photos and Carousels

Instagram posts come in three shapes: a Reel (one video), a photo post (one image), and a carousel (up to twenty of either, freely mixed). The FastSaver API fetches all three with the same GET request — two fields in the response, kind and type, tell you which one you got. Here is each shape as real JSON, the errors you will actually see, and the operational notes that never make it onto a pricing page.

The call

curl "https://api.fastsaver.io/v1/fetch?url=https://www.instagram.com/reel/DRVO0TKkWPD/" \
  -H "X-Api-Key: YOUR_KEY"

Reel links and /p/ post links go through the same endpoint. You never need to detect the post type up front — the response tells you what it found.

Reels and feed videos

{
  "platform": "instagram",
  "kind": "single",
  "title": "golden hour in lisbon",
  "author": "@joana.films",
  "thumbnail": "https://scontent.cdninstagram.com/v/512204981_n.jpg?…",
  "duration": 31,
  "medias": [
    {
      "type": "video",
      "quality": "auto",
      "ext": "mp4",
      "url": "https://scontent.cdninstagram.com/v/512204981_n.mp4?…",
      "size": 8388608
    }
  ]
}

kind: "single" means one post, one downloadable file — but medias is always an array, so read the first entry rather than special-casing. quality: "auto" is the source file as the creator uploaded it: nothing re-encoded, no watermark added, original audio intact. duration is in seconds; size is in bytes and only present when known, so treat it as optional. A feed video — one posted to the grid rather than as a Reel — comes back in the identical shape. Instagram barely distinguishes the two any more, and neither does the response.

Photo posts

Same shape, two differences: the media entry has type: "image" with an ext of jpg, and there is no duration. That is the entire branch your code needs to handle.

Carousels

{
  "platform": "instagram",
  "kind": "album",
  "title": "porto in five frames",
  "author": "@joana.films",
  "thumbnail": "https://scontent.cdninstagram.com/v/468120334.jpg?…",
  "medias": [
    {
      "type": "image",
      "quality": "image",
      "ext": "jpg",
      "url": "https://scontent.cdninstagram.com/v/468120334.jpg?…",
      "thumbnail": "https://scontent.cdninstagram.com/v/468120334_t.jpg?…"
    },
    {
      "type": "video",
      "quality": "auto",
      "ext": "mp4",
      "url": "https://scontent.cdninstagram.com/v/468121077.mp4?…",
      "thumbnail": "https://scontent.cdninstagram.com/v/468121077_t.jpg?…"
    }
  ]
}

kind: "album", one medias entry per slide, in the order they appear in the app. Two rules save you from real bugs here. Check type per entry, not per post — mixed photo/video albums are completely normal on Instagram. And use the per-item thumbnail to render a picker, so users can choose slides before you download twenty files they didn't want.

Thumbnails expire — plan for it

Every response carries a top-level thumbnail (the cover image), and album entries each carry their own. All of these — the download URLs included — are signed Instagram CDN links with an expiry baked in. Fetch what you need when the response arrives and store the file. A URL saved to your database will start returning 403 sooner than you'd like; when you need the media again later, re-fetch the post instead of hoarding links.

Public posts only, and what failure looks like

{
  "error": true,
  "code": "unreachable",
  "message": "this post can't be reached — it may be private or deleted"
}

Private accounts, Stories and deleted posts all land here: an error: true body with a machine-readable code and a short human-readable message you can show as-is. The codes worth branching on:

  • unreachable — private, deleted, or otherwise unfetchable. Not retryable; tell the user.
  • unsupported — the URL isn't a supported platform link. Fix the input, not the request.
  • rate_limited — HTTP 429. Read the retry-after header and actually wait that long.
  • server_error — our side. Retry once after a short delay.

There is no workaround for private content, by design — don't build a feature that depends on it. Plenty of products live happily on the public side; here are six of them.

Rate limits

Successful responses include an x-ratelimit-remaining header, so you can watch your budget instead of discovering it at zero. When you do run out, the 429 comes with retry-after in seconds. Back off for exactly that long — hammering a rate limiter never once has un-limited anyone.

Honest notes on Instagram specifically

Of every platform FastSaver supports, Instagram breaks the most often. It ships anti-scraping changes constantly, and every downloader on the internet — ours included — plays catch-up when it does. In practice that means occasional windows where Instagram fetches degrade while the extractor is updated, usually measured in hours. Build for it: retry a failed fetch once, then surface the error instead of looping; monitor your error rate rather than assuming up-or-down. The API absorbs this churn so you don't maintain an extractor yourself, but nobody can promise 100% on Instagram — a vendor who does is lying to you.

API or web downloader?

If you're saving one Reel for yourself, skip all of this — the web downloader is the same engine with a paste box, and there are short guides for Reels and photos. The API is for building: Telegram bots, archival tools, content pipelines. Auth and the full endpoint reference live in the getting started guide, and keys come from api.fastsaver.io.

Frequently asked questions

How do I tell a Reel from a photo post in the response?
Check kind and the media type. Both are kind "single"; a Reel's media entry has type "video" with a duration, a photo post has type "image" and no duration.
How do Instagram carousels come back?
As kind "album" with one medias entry per slide, each carrying its own type, url and thumbnail. Mixed photo/video albums are normal — branch on type per entry.
What happens when a post is private or deleted?
You get an error body: error true, code "unreachable", and a short message you can show directly. Public posts only — there is no workaround, by design.
Can I store the returned URLs and download later?
No. Download and thumbnail URLs are signed Instagram CDN links that expire. Fetch the files when you get the response; re-fetch the post if you need them again.
Why did a fetch that worked yesterday fail today?
Instagram changes its defenses more often than any other supported platform. Failures are usually a short window while the extractor updates — retry once, then surface the error.