# Instagram API documentation

Everything you need to call the StoriesFly API: how to get a key and make a first request, the rules for authentication, paging, errors and rate limits, and a page for each of the 43 data endpoints, and one for the free `account` call, with its parameters, a real sample answer and code to copy. The whole API is also described in [openapi.json](https://storiesfly.com/openapi.json).

## Quick start

Sign in with Telegram in the [dashboard](https://storiesfly.com/developers/dashboard) and create a key. A new account gets 100 free requests, so you can try the endpoints before you pay.

Then send a `GET` request to `https://storiesfly.com/api/v1/` with the key in the `X-Api-Key` header. This call reads the profile of an account and takes 1 request.

**cURL**

```bash
curl "https://storiesfly.com/api/v1/user/profile?username=arianagrande" \
  -H "X-Api-Key: sf_live_your_key"
```

## The first answer

The answer is JSON. The headers say what the call cost: `X-Units-Charged: 1`, and what is left in `X-Balance-Remaining` and `X-Free-Units-Remaining`. Long texts and links are shortened in this example.

**Response**

```json
{
  "id": "7719696",
  "username": "arianagrande",
  "full_name": "Ariana Grande",
  "bio": "petal out now ꕤ ｡˚",
  "followers": 362337023,
  "following": 1075,
  "posts": 599,
  "verified": true,
  "is_private": false,
  "profile_pic_url": "https://scontent-iad3-1.cdninstagram.com/v/t51.82787-19/758252911_18764924023039697_5331858031316748508_n.jpg",
  "external_url": "https://linktr.ee/arianagrande"
}
```

## Official client

For Node.js 18 or newer and for TypeScript there is an official client on npm. It has a method for every Instagram endpoint; call the TikTok endpoints and `download` over HTTP for now. It sends the `X-Api-Key` header, follows `next_cursor` through a list, retries a `429` after the wait the API asks for, types every answer and returns the cost of a call and your balance in the response meta.

Each page of a list is charged as one call, so set `maxPages` unless you mean to read the whole list. For other languages, call the API with cURL as above, or generate a client from [openapi.json](https://storiesfly.com/openapi.json).

**Install**

```bash
npm install storiesfly
```

**Stories of an account**

```typescript
import { StoriesFly } from "storiesfly";

const sf = new StoriesFly({ apiKey: process.env.STORIESFLY_KEY! });

const { stories } = await sf.user.stories({ username: "brooklynandbailey" });
```

**The pages of a list**

```typescript
for await (const page of sf.paginate(sf.user.followers, { username: "arianagrande" }, { maxPages: 4 })) {
  console.log(page.users.length);
}
```

- [storiesfly on npm](https://www.npmjs.com/package/storiesfly)
- [storiesfly on GitHub](https://github.com/coolpac/storiesfly-api-client)

## Authentication

Send your key in the `X-Api-Key` header of every call. There is no login and no token exchange, and you do not need an Instagram or Facebook account.

A missing or wrong key answers `unauthorized` (HTTP 401). A key whose account is not linked to Telegram answers `telegram_required` with a `link_url` to do it. Keep the key on your server, because anyone who has it can spend your balance. You can replace and revoke keys in the [dashboard](https://storiesfly.com/developers/dashboard).

Every endpoint is a `GET` under `https://storiesfly.com/api/v1/`, and its parameters go in the query string.

## Pagination

An endpoint that returns a list sends it a page at a time. The answer has `next_cursor` and `has_more`.

To get the next page, send the `next_cursor` back as `cursor` and keep every other parameter the same: `https://storiesfly.com/api/v1/user/following?username=arianagrande&cursor=<next_cursor>`. When `has_more` is `false`, `next_cursor` is `null` and the list has ended.

A cursor is an opaque text. Do not build or change one: a cursor that the endpoint did not return answers `bad_request`. Each page takes the price of one call.

Page size follows Instagram and varies by endpoint. The page of an endpoint says how many items a page holds where we measured it.

**A page of a list**

```json
{
  "user": {
    "id": "7719696",
    "username": "arianagrande"
  },
  "users": [
    {
      "id": "1000000012",
      "username": "sample_user_16",
      "full_name": "Sample Name",
      "profile_pic_url": "https://example.com/pic.jpg",
      "verified": true,
      "is_private": false
    }
  ],
  "next_cursor": "c1.ryg6VkAgkE2BcPyGM0q6ADwLG1KAGWvXyxXcleap6rtdnm6USXXD4rRRujLUjticHxS2vixe2jbdlG4LggGvIE1ISp6sYLXI6XWcb66UIrM_RMPDKCUhQylnCgNoMsPrfzM",
  "has_more": true
}
```

## Errors and what is charged

A failed call answers with an HTTP status and a JSON body `{error, code}`. `error` is a sentence for people and `code` is the value to test for in your program. A refused parameter also lists its names in `fields`.

You are charged for answers: the data, `not_found` and `private_account`. A wrong parameter, a rate limit and an empty balance cost nothing, and a failure on our side is refunded. Most data calls take 1 request at your level's rate, and resolving a share link takes 2. `download` has a fixed price at every level instead: $0.20 per 1,000 for a TikTok link, $0.50 per 1,000 for an Instagram link. A download uses one free request while you have free requests left. The page of each endpoint says what its call takes.

| Status | Code | Charged | When |
| --- | --- | --- | --- |
| `200` | `ok` | charged | The data you asked for |
| `404` | `not_found` | charged | The account or post does not exist |
| `403` | `private_account` | charged | The account is private |
| `400` | `bad_request` | free | A parameter is missing or wrong |
| `402` | `credits_exhausted` | free | Top up to continue |
| `429` | `rate_limited` | free | Too fast; wait for `Retry-After` |
| `503` | `upstream_unavailable` | refunded | Our side failed or timed out |
| `401` | `unauthorized` | free | The `X-Api-Key` header is missing or the key is wrong |
| `403` | `telegram_required` | free | The account behind the key is not linked to Telegram; the answer has a `link_url` |
| `500` | `internal_error` | refunded | A fault on our side |

**An error**

```json
{
  "error": "The request parameters are missing or invalid.",
  "code": "bad_request",
  "fields": [
    "username"
  ]
}
```

## Rate limits

Your level sets how many requests per second you may send, for all your keys together. A call over the limit answers `rate_limited` (HTTP 429) with a `Retry-After` header, and costs nothing. `X-RateLimit-Limit` and `X-RateLimit-Remaining` show the limit on every answer.

Levels above Start are not open yet. The default limits today are 1 request per second for an account that has not topped up yet and 3 requests per second at Start. Prices are on the [pricing page](https://storiesfly.com/developers/pricing).

Higher limits are set by agreement, for example for large volumes. [Write to us](https://storiesfly.com/contact).

| Level | Reached by | Requests per second | Status |
| --- | --- | --- | --- |
| Free | Signing in with Telegram | 1 | Open |
| Start | Top up from $10 | 3 | Open |
| Growth | Top-ups totalling $100 | 5 | Opens soon |
| Business | Top-ups totalling $300 | 10 | Opens soon |
| Scale | Top-ups totalling $1,000 | 15 | Opens soon |

## Response headers

An answer to a call that reaches your account carries these headers, so your code can read what the call cost and what is left. `X-Request-Id` is on every answer, errors included. Quote it when you write to support about a call.

| Header | Type | Meaning |
| --- | --- | --- |
| `X-Units-Charged` | integer | Units this call charged. 0 when it was free or was refunded. |
| `X-Balance-Remaining` | string | Your balance after the call, in US dollars with four decimals. |
| `X-Free-Units-Remaining` | integer | Free units you have left after the call. |
| `X-RateLimit-Limit` | integer | How many requests per second your account may send. |
| `X-RateLimit-Remaining` | integer | Requests left in the current second. |
| `X-Request-Id` | string | The id of this call. Quote it when you write to support about the call. |

## Endpoints

43 data endpoints and the free `account` call that shows your balance, all `GET`, grouped as on the [API page](https://storiesfly.com/developers). Each has a page with its parameters, a real sample answer, the errors it can give and code in cURL, JavaScript and Python, and for the Instagram endpoints the npm client as well.

## User

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/user/profile](https://storiesfly.com/developers/docs/user-profile) | Profile with verified badge, bio, link and counts | 1 |
| [GET /v1/user/about](https://storiesfly.com/developers/docs/user-about) | Country, join month and former usernames | 1 |
| [GET /v1/user/posts](https://storiesfly.com/developers/docs/user-posts) | Posts with likes, comments, views, shares, saves and reposts | 1 |
| [GET /v1/user/reels](https://storiesfly.com/developers/docs/user-reels) | Reels with captions, video and play counts | 1 |
| [GET /v1/user/tagged](https://storiesfly.com/developers/docs/user-tagged) | Posts the account is tagged in | 1 |
| [GET /v1/user/pinned](https://storiesfly.com/developers/docs/user-pinned) | Posts pinned to the top of the profile | 1 |
| [GET /v1/user/stories](https://storiesfly.com/developers/docs/user-stories) | Stories live now, with the length of each video | 1 |
| [GET /v1/user/highlights](https://storiesfly.com/developers/docs/user-highlights) | Highlight covers and titles | 1 |
| [GET /v1/user/followers](https://storiesfly.com/developers/docs/user-followers) | Followers, page by page | 1 |
| [GET /v1/user/following](https://storiesfly.com/developers/docs/user-following) | Accounts followed, page by page | 1 |
| [GET /v1/user/followers/search](https://storiesfly.com/developers/docs/user-followers-search) | Find someone among the followers | 1 |
| [GET /v1/user/following/search](https://storiesfly.com/developers/docs/user-following-search) | Find someone among the accounts followed | 1 |
| [GET /v1/user/reposts](https://storiesfly.com/developers/docs/user-reposts) | Posts and reels the account reposted | 1 |
| [GET /v1/user/suggested](https://storiesfly.com/developers/docs/user-suggested) | Similar accounts Instagram suggests | 1 |

## Post

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/post](https://storiesfly.com/developers/docs/post) | One post: media links, caption, views, likes, comments, shares, saves and reposts | 1 |
| [GET /v1/post/comments](https://storiesfly.com/developers/docs/post-comments) | Comments with likes and reply counts | 1 |
| [GET /v1/post/comment-replies](https://storiesfly.com/developers/docs/post-comment-replies) | Replies to a comment | 1 |
| [GET /v1/post/likers](https://storiesfly.com/developers/docs/post-likers) | Accounts that liked the post | 1 |
| [GET /v1/post/usertags](https://storiesfly.com/developers/docs/post-usertags) | People tagged in the post | 1 |
| [GET /v1/post/music](https://storiesfly.com/developers/docs/post-music) | The track used in a reel | 1 |
| [GET /v1/comment/likers](https://storiesfly.com/developers/docs/comment-likers) | Accounts that liked a comment | 1 |

## Stories

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/story](https://storiesfly.com/developers/docs/story) | One story by link or id | 1 |
| [GET /v1/highlight](https://storiesfly.com/developers/docs/highlight) | Every story in a highlight, by link or id | 1 |

## Hashtags

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/hashtag](https://storiesfly.com/developers/docs/hashtag) | A hashtag with its post count | 1 |
| [GET /v1/hashtag/posts](https://storiesfly.com/developers/docs/hashtag-posts) | Posts under a hashtag: top, recent or reels | 1 |

## Places

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/location](https://storiesfly.com/developers/docs/location) | Place name, address, city and coordinates | 1 |
| [GET /v1/location/posts](https://storiesfly.com/developers/docs/location-posts) | Posts tagged at a place: top or recent | 1 |
| [GET /v1/location/search](https://storiesfly.com/developers/docs/location-search) | Find places by name or around a point | 1 |

## Search

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/search/users](https://storiesfly.com/developers/docs/search-users) | Find accounts by name or username | 1 |
| [GET /v1/search/hashtags](https://storiesfly.com/developers/docs/search-hashtags) | Find hashtags, with their post counts | 1 |
| [GET /v1/search/places](https://storiesfly.com/developers/docs/search-places) | Find places by name | 1 |
| [GET /v1/search/music](https://storiesfly.com/developers/docs/search-music) | Find tracks by title or artist | 1 |
| [GET /v1/search/reels](https://storiesfly.com/developers/docs/search-reels) | Find reels for a text | 1 |
| [GET /v1/search/top](https://storiesfly.com/developers/docs/search-top) | The top posts for a text | 1 |

## TikTok

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/tiktok/video](https://storiesfly.com/developers/docs/tiktok-video) | One TikTok video without the watermark, with views, likes, comments and shares | 1 |
| [GET /v1/tiktok/user/profile](https://storiesfly.com/developers/docs/tiktok-user-profile) | TikTok profile with followers, following, likes and video count | 1 |
| [GET /v1/tiktok/user/videos](https://storiesfly.com/developers/docs/tiktok-user-videos) | A TikTok account's latest videos with their numbers | 1 |
| [GET /v1/tiktok/user/stories](https://storiesfly.com/developers/docs/tiktok-user-stories) | TikTok stories live now | 1 |

## Download

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/download](https://storiesfly.com/developers/docs/download) | Files of an Instagram post or reel, or a TikTok video, by link | 1 |

## Other

| Endpoint | What it returns | Requests |
| --- | --- | --- |
| [GET /v1/track](https://storiesfly.com/developers/docs/track) | Track title, artist, length and audio link | 1 |
| [GET /v1/resolve](https://storiesfly.com/developers/docs/resolve) | Turn a post, reel or share link into data | 1, or 2 for a share link |
| [GET /v1/shop/storefront](https://storiesfly.com/developers/docs/shop-storefront) | An account's shop: collections and first products | 1 |
| [GET /v1/shop/products](https://storiesfly.com/developers/docs/shop-products) | Products in a shop collection | 1 |
| [GET /v1/account](https://storiesfly.com/developers/docs/account) | Your plan, balance, free units and use | 0 |

## More

- The whole API in one file: [openapi.json](https://storiesfly.com/openapi.json), OpenAPI 3.1, for code generators and API clients.
- [Pricing](https://storiesfly.com/developers/pricing) has the levels from $1.50 per 1,000 requests, the billing rules and how to pay. The [changelog](https://storiesfly.com/developers/changelog) lists what changed and when.
- Reading stories? See the [Instagram Stories API](https://storiesfly.com/developers/instagram-stories-api). Wondering about a login? See the [API without login](https://storiesfly.com/developers/instagram-api-without-login).
- The endpoints that came before v1 are on the [older endpoints](https://storiesfly.com/developers/docs/legacy) page, with the date they stop.

## Links

- [This page on the site](https://storiesfly.com/developers/docs)
- [See pricing](https://storiesfly.com/developers/pricing)
- [Instagram data API](https://storiesfly.com/developers): what the API is and what it returns
- [OpenAPI file](https://storiesfly.com/openapi.json): the whole API in one file
- [API dashboard](https://storiesfly.com/developers/dashboard): get a key and top up
- [Changelog](https://storiesfly.com/developers/changelog): what changed and when
