# Instagram API for agents

> API for Agents · https://apiforagents.dev/platforms/instagram · HTML twin: https://apiforagents.dev/platforms/instagram

Profiles, posts, comments, followers, hashtags and similar accounts from Instagram.

Endpoint: `POST https://apiforagents.dev/v1/instagram`. One op per call. Quote first with `"estimateOnly": true`.

## Prices (USD per record, pay as you go)

| Record | Per record |
|---|---|
| comments | $0.00045 |
| followers | $0.000675 |
| posts | $0.0018 |
| profiles | $0.0018 |

## Operations

### profiles

Profile cards for up to ten accounts. Profile-only by default. A call that also wants each account's recent posts says `include.posts` and gets profiles AND posts in one call, one answer.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) | Usernames or profile URLs. |
| fields | no | list of enum | 'contact' adds the business email/phone fields to the answer; the fetch is the same either way, so this shapes the RESPONSE, not the bill. Values: profile, contact. |
| include | no | object |  |
| include.posts | no | object |  |
| include.posts.limit | no | integer (1-48) | Recent posts to fetch per account, newest first; 1-48. |
| include.posts.tab | no | enum | Which tab to read: the grid ("posts") or Reels ("reels"). Values: posts, reels. |
| include.posts.since | no | string (YYYY-MM-DD) | Only posts on or after this day (YYYY-MM-DD). Omit for the newest. |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| username | string |
| igUserId | string |
| fullName | string |
| biography | string |
| avatarUrl | string |
| profileUrl | string |
| externalUrl | string |
| bioLinks | list of object |
| category | string |
| isVerified | boolean |
| isPrivate | boolean |
| isBusiness | boolean |
| followers | integer |
| following | integer |
| mediaCount | integer |
| highlightReelCount | integer |
| engagementRate | number |
| contactEmail | string |
| contactPhone | string |
| location | string |
| businessStreet | string |
| businessZip | string |
| businessCityId | string |
| businessLatitude | number |
| businessLongitude | number |
| facebookPage | object |
| lastPostedAt | string |
| recentPosts | list of object |
| relatedAccounts | list of object |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/instagram \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"profiles","subjects":["natgeo","nike"]}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "username": "brewlab.coffee",
    "fullName": "Brewlab Coffee",
    "biography": "Small-batch roasters · Austin, TX",
    "category": "Coffee shop",
    "isVerified": false,
    "isBusiness": true,
    "followers": 48210,
    "following": 312,
    "mediaCount": 864,
    "engagementRate": 0.031,
    "location": "Austin, Texas",
    "igUserId": "456125832",
    "avatarUrl": "https://img.instagram.com/brewlab-coffee.jpg",
    "externalUrl": "https://www.instagram.com/brewlab-coffee-1000",
    "isPrivate": false,
    "lastPostedAt": "2026-10-05",
    "details": {}
  },
  {
    "username": "mira.moves",
    "fullName": "Mira | Pilates",
    "biography": "Pilates for busy people · new class every Monday",
    "category": "Fitness trainer",
    "isVerified": true,
    "isBusiness": true,
    "followers": 182400,
    "following": 540,
    "mediaCount": 1210,
    "engagementRate": 0.046,
    "location": "Mumbai, India",
    "igUserId": "908365941",
    "avatarUrl": "https://img.instagram.com/mira-pilates.jpg",
    "externalUrl": "https://www.instagram.com/mira-pilates-1001",
    "isPrivate": false,
    "lastPostedAt": "2026-10-11",
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=profiles (sign in first).

### posts

One account's recent posts, newest first. The grid or the Reels tab. With the author's profile card in the same answer.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subject | yes | string (≤400 chars) | One username or profile URL. |
| limit | no | integer (1-48) |  |
| tab | no | enum | 'reels' pulls the Reels tab instead of the grid. Non-default tabs and date floors always fetch fresh (they never touch the grid's cache markers) and are served fresh from a source that has them. Values: posts, reels. |
| since | no | string (YYYY-MM-DD) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| shortCode | string |
| igMediaId | string |
| caption | string |
| kind | string |
| productType | string |
| postedAt | string |
| permalink | string |
| mediaUrl | string |
| videoUrl | string |
| images | list of string |
| media | list of object |
| width | integer |
| height | integer |
| likes | integer |
| comments | integer |
| views | integer |
| plays | integer |
| saves | integer |
| shares | integer |
| videoDuration | number |
| language | string |
| likesHidden | boolean |
| isPinned | boolean |
| isPaidPartnership | boolean |
| hashtags | list of string |
| mentions | list of string |
| owner | object |
| taggedUsers | list of object |
| coauthors | list of object |
| sponsors | list of object |
| locationName | string |
| locationId | string |
| music | object |
| firstComment | string |
| recentComments | list of object |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/instagram \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"posts","subject":"natgeo","limit":12}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "owner": {
      "username": "brewlab.coffee"
    },
    "caption": "New single origin from Chikmagalur ☕ #specialtycoffee",
    "kind": "image",
    "postedAt": "2026-10-15T08:00:00Z",
    "likes": 2140,
    "comments": 88,
    "hashtags": [
      "specialtycoffee"
    ],
    "views": null,
    "videoDuration": null,
    "igMediaId": "1315471224",
    "permalink": "https://www.instagram.com/new-single-origin-from-chikmagalur-speci-1000",
    "mediaUrl": "https://www.instagram.com/new-single-origin-from-chikmagalur-speci-1000",
    "isPinned": false,
    "isPaidPartnership": false,
    "details": {}
  },
  {
    "owner": {
      "username": "brewlab.coffee"
    },
    "caption": "How we dial in espresso every morning",
    "kind": "reel",
    "postedAt": "2026-10-12T07:30:00Z",
    "likes": 5310,
    "comments": 142,
    "hashtags": [
      "espresso",
      "baristalife"
    ],
    "views": 88400,
    "videoDuration": 41,
    "igMediaId": "1973392646",
    "permalink": "https://www.instagram.com/how-we-dial-in-espresso-every-morning-1001",
    "mediaUrl": "https://www.instagram.com/how-we-dial-in-espresso-every-morning-1001",
    "isPinned": false,
    "isPaidPartnership": false,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=posts (sign in first).

### similar

Accounts related to one account, for finding more like it.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subject | yes | string (≤400 chars) | One username or profile URL. |
| limit | no | integer (1-50) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| username | string |
| fullName | string |
| igUserId | string |
| isVerified | boolean |
| isPrivate | boolean |
| avatarUrl | string |
| profileUrl | string |
| followers | integer |
| profile | object |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/instagram \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"similar","subject":"natgeo","limit":20}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "username": "roastery.co",
    "fullName": "Roastery Co.",
    "followers": 61200,
    "details": {}
  },
  {
    "username": "dailygrind.cafe",
    "fullName": "Daily Grind",
    "followers": 23400,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=similar (sign in first).

### hashtag

Posts TAGGED with a hashtag. Instagram's public listening surface. 'top' is the ranked timeline; 'newest' is chronological.

| Field | Required | Type | Meaning |
|---|---|---|---|
| hashtag | yes | string (≤150 chars) |  |
| sort | no | enum |  Values: top, newest. |
| limit | no | integer (1-50) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| shortCode | string |
| igMediaId | string |
| caption | string |
| kind | string |
| productType | string |
| postedAt | string |
| permalink | string |
| mediaUrl | string |
| videoUrl | string |
| images | list of string |
| media | list of object |
| width | integer |
| height | integer |
| likes | integer |
| comments | integer |
| views | integer |
| plays | integer |
| saves | integer |
| shares | integer |
| videoDuration | number |
| language | string |
| likesHidden | boolean |
| isPinned | boolean |
| isPaidPartnership | boolean |
| hashtags | list of string |
| mentions | list of string |
| owner | object |
| taggedUsers | list of object |
| coauthors | list of object |
| sponsors | list of object |
| locationName | string |
| locationId | string |
| music | object |
| firstComment | string |
| recentComments | list of object |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/instagram \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"hashtag","hashtag":"streetphotography","sort":"top","limit":20}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "owner": {
      "username": "mira.moves"
    },
    "caption": "10-minute core flow, save it for later #pilates",
    "kind": "reel",
    "postedAt": "2026-10-13T06:00:00Z",
    "likes": 18250,
    "comments": 412,
    "views": 241000,
    "videoDuration": 58,
    "hashtags": [
      "pilates",
      "corestrength"
    ],
    "igMediaId": "2465709650",
    "permalink": "https://www.instagram.com/10-minute-core-flow-save-it-for-later-pi-1000",
    "mediaUrl": "https://www.instagram.com/10-minute-core-flow-save-it-for-later-pi-1000",
    "isPinned": false,
    "isPaidPartnership": false,
    "details": {}
  },
  {
    "owner": {
      "username": "studio.flow"
    },
    "caption": "Reformer basics for week one #pilates",
    "kind": "reel",
    "postedAt": "2026-10-12T17:20:00Z",
    "likes": 6400,
    "comments": 120,
    "views": 91200,
    "videoDuration": 33,
    "hashtags": [
      "pilates",
      "reformer"
    ],
    "igMediaId": "1592716932",
    "permalink": "https://www.instagram.com/reformer-basics-for-week-one-pilates-1001",
    "mediaUrl": "https://www.instagram.com/reformer-basics-for-week-one-pilates-1001",
    "isPinned": false,
    "isPaidPartnership": false,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=hashtag (sign in first).

### search

Instagram's own account search. Find handles by name or keyword.

| Field | Required | Type | Meaning |
|---|---|---|---|
| query | yes | string (≤300 chars) |  |
| limit | no | integer (1-25) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| username | string |
| fullName | string |
| igUserId | string |
| isVerified | boolean |
| isPrivate | boolean |
| avatarUrl | string |
| profileUrl | string |
| followers | integer |
| profile | object |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/instagram \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"search","query":"coffee roasters","limit":10}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "username": "mira.moves",
    "fullName": "Mira | Pilates",
    "followers": 182400,
    "details": {}
  },
  {
    "username": "corewithkai",
    "fullName": "Kai Tan",
    "followers": 96300,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=search (sign in first).

### comments

Top comments on up to ten Instagram POSTS, by /p/ or /reel/ URL (or a bare shortcode). Author is free text. Commenters are not corpus members.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) | Post URLs (/p/ or /reel/) or bare shortcodes. |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| igCommentId | string |
| author | string |
| body | string |
| score | integer |
| commentedAt | string |
| commenter | object |
| replyCount | integer |
| commentUrl | string |
| postUrl | string |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/instagram \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"comments","subjects":["https://www.instagram.com/p/<shortcode>/"],"limit":50}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "author": "ravi.k",
    "body": "Tried this today, so good!",
    "score": 42,
    "commentedAt": "2026-10-15T09:10:00Z",
    "igCommentId": "1406279790",
    "details": {}
  },
  {
    "author": "lena_m",
    "body": "Which beans do you use?",
    "score": 18,
    "commentedAt": "2026-10-15T09:44:00Z",
    "igCommentId": "3977780793",
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=comments (sign in first).

### followers

The followers OR the following list of up to ten public accounts. The discovered accounts become thin corpus rows and a directed follow edge.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) | Usernames or profile URLs. |
| direction | no | enum |  Values: followers, following. |
| limit | no | integer (1-100) |  |

Response fields (each row of data; every field present, null when the source had nothing):

| Field | Type |
|---|---|
| username | string |
| fullName | string |
| igUserId | string |
| isVerified | boolean |
| isPrivate | boolean |
| avatarUrl | string |
| profileUrl | string |
| followers | integer |
| profile | object |
| details | object |

`details` is always the last field: everything else the source sent for that row, under our own field names. Its keys depend on the source that answered, so read them defensively; it is `{}` when there is nothing more.

Example request:

```bash
curl -X POST https://apiforagents.dev/v1/instagram \
  -H "Authorization: Bearer $AFA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"op":"followers","subjects":["natgeo"],"direction":"following","limit":50}'
```

Example response rows (made-up names, real field names; a live row carries every field above):

```json
[
  {
    "username": "ravi.k",
    "fullName": "Ravi Kumar",
    "followers": 412,
    "details": {}
  },
  {
    "username": "lena_m",
    "fullName": "Lena M.",
    "followers": 2100,
    "details": {}
  }
]
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=followers (sign in first).

### history (free)

The stored time series. Free, reads only what captures already wrote.

| Field | Required | Type | Meaning |
|---|---|---|---|
| subjects | yes | list of string (1-10 items) | Usernames or profile URLs. |
| metric | no | enum |  Values: followers, following, media_count, engagement_rate. |
| days | no | integer (1-730) |  |

Request shape:

```json
{
  "op": "history",
  "subjects": [
    "example"
  ]
}
```

Try it in the playground: https://apiforagents.dev/dashboard/run?platform=instagram&op=history (sign in first).

## Notes for the agent

Measured Instagram data, one operation per call. Usernames come from evidence (a search result, a pasted URL, a prior answer). Never typed from a person's name. ops: profiles (subjects = usernames; add include.posts to get each account's recent posts IN THE SAME CALL. Profiles with posts of each, one answer), posts (one account, deep. Includes the author's profile card), similar (related accounts), hashtag (posts tagged #x, sort top/newest), search (find accounts by keyword), comments (top comments on posts by URL), followers (the followers OR following list of accounts), history (stored time series, free). Ops are independent. Issue several as PARALLEL tool calls for faster answers. Fresh fetches are charged per record; your own answer is free while fresh.
