> For the complete documentation index, see [llms.txt](https://docs.pullbay.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.pullbay.com/documentation/api-and-references/instagram.md).

# Instagram

The Pullbay Instagram API provides programmatic access to public Instagram profile, post, reel, story, and comment data. Resolve handles to user IDs, pull a profile, list a user's posts/tagged posts/reels, read active stories, fetch a single post by shortcode, or pull comments on a post — all without scraping or owning an Instagram account of your own.

**Base URL:** `https://api.pullbay.com`

## Overview

The Instagram service lets you:

* Resolve a handle (`@username`) to Instagram's internal numeric user ID
* Look up a full user profile by handle or by numeric ID
* List a user's posts, posts they're tagged in, and reels (cursor-paginated)
* Fetch a user's currently-active stories
* Fetch a single post by its shortcode (the code in an `instagram.com/p/{code}/` URL)
* Fetch comments on a post by the post's internal ID (cursor-paginated)

All endpoints are read-only `GET` requests against public Instagram data — no account of your own is required. This service uses **three distinct identifier types that are not interchangeable**: `handle` (the `@username`, passed without the `@`), `id` (Instagram's internal numeric ID for a user, post, or comment), and `code` (a post's shortcode, the segment after `/p/` in a post URL). Always check which one a given endpoint expects.

## Common Use Cases

**Influencer Vetting** — Pull a creator's profile (follower count, post count, verification status) before negotiating a sponsorship, and check their recent posts for content fit and engagement levels.

**Engagement Tracking** — Poll a brand or creator account's posts and reels on a schedule to track `likeCount` and `commentCount` trends over time.

**Campaign Monitoring** — Fetch posts a brand account is tagged in to see how a hashtag or partnership campaign is performing across other accounts.

**Comment Sentiment Analysis** — Pull comments on a post and feed the `message` field into your own sentiment or moderation pipeline.

**Story Archiving** — Capture a user's active stories before they expire (24 hours after posting) for compliance, reporting, or content-repurposing workflows.

## Endpoints

| Endpoint                                | Description                           | Pagination        |
| --------------------------------------- | ------------------------------------- | ----------------- |
| `GET /instagram/userid/{handle}`        | Resolve a handle to a numeric user ID | —                 |
| `GET /instagram/user/handle/{handle}`   | Get a user profile by handle          | —                 |
| `GET /instagram/user/{id}`              | Get a user profile by numeric ID      | —                 |
| `GET /instagram/user/{id}/posts`        | Get posts published by a user         | Cursor / maxItems |
| `GET /instagram/user/{id}/posts/tagged` | Get posts a user is tagged in         | Cursor / maxItems |
| `GET /instagram/user/{id}/reels`        | Get reels published by a user         | Cursor / maxItems |
| `GET /instagram/user/{id}/stories`      | Get a user's currently-active stories | —                 |
| `GET /instagram/post/code/{code}`       | Get a single post by shortcode        | —                 |
| `GET /instagram/post/{id}/comments`     | Get comments on a post                | Cursor / maxItems |

***

### Resolve User ID

Returns whether a handle is available and, if it exists, the resolved Instagram user ID.

**Request**

```http
GET /instagram/userid/{handle}
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter | Type          | Required | Default | Description                                                        |
| --------- | ------------- | -------- | ------- | ------------------------------------------------------------------ |
| `handle`  | string (path) | Yes      | —       | Instagram handle, without `@`, 1–100 characters (e.g. `instagram`) |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/userid/instagram" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "isAvailable": true,
      "handle": "instagram",
      "id": "25025320"
    }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                    | Type   | Description                                                               |
| ------------------------ | ------ | ------------------------------------------------------------------------- |
| `data`                   | array  | Array containing a single [User ID lookup object](#user-id-lookup-object) |
| `pricing.creditsCharged` | number | Credits charged for this request                                          |

**Credit cost:** charged dynamically per request; the exact amount is always returned in `pricing.creditsCharged`. No published flat rate — read the figure from the response.

***

### Get User By Handle

Returns an Instagram user profile by handle (without `@`).

**Request**

```http
GET /instagram/user/handle/{handle}
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter | Type          | Required | Default | Description                                                        |
| --------- | ------------- | -------- | ------- | ------------------------------------------------------------------ |
| `handle`  | string (path) | Yes      | —       | Instagram handle, without `@`, 1–100 characters (e.g. `instagram`) |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/user/handle/instagram" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "user",
      "isAvailable": true,
      "id": "25025320",
      "username": "instagram",
      "fullName": "Instagram",
      "biography": "Discover what's new on Instagram 🔎✨",
      "profilePicUrl": "https://instagram.com/static/images/profile.jpg",
      "website": "https://about.instagram.com",
      "category": "App page",
      "cityName": null,
      "isPrivate": false,
      "isVerified": true,
      "isBusiness": true,
      "hasVideos": true,
      "hasGuides": false,
      "postCount": 8200,
      "followerCount": 689000000,
      "followingCount": 264,
      "totalReelsCount": 1850,
      "bioLinks": []
    }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                    | Type   | Description                                           |
| ------------------------ | ------ | ----------------------------------------------------- |
| `data`                   | array  | Array containing a single [User object](#user-object) |
| `pricing.creditsCharged` | number | Credits charged for this request                      |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate.

***

### Get User By ID

Returns an Instagram user profile by numeric user ID.

**Request**

```http
GET /instagram/user/{id}
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter | Type          | Required | Default | Description                                                   |
| --------- | ------------- | -------- | ------- | ------------------------------------------------------------- |
| `id`      | string (path) | Yes      | —       | Numeric Instagram user ID, 1–100 characters (e.g. `25025320`) |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/user/25025320" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "user",
      "isAvailable": true,
      "id": "25025320",
      "username": "instagram",
      "fullName": "Instagram",
      "biography": "Discover what's new on Instagram 🔎✨",
      "profilePicUrl": "https://instagram.com/static/images/profile.jpg",
      "website": "https://about.instagram.com",
      "category": "App page",
      "cityName": null,
      "isPrivate": false,
      "isVerified": true,
      "isBusiness": true,
      "hasVideos": true,
      "hasGuides": false,
      "postCount": 8200,
      "followerCount": 689000000,
      "followingCount": 264,
      "totalReelsCount": 1850,
      "bioLinks": []
    }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                    | Type   | Description                                           |
| ------------------------ | ------ | ----------------------------------------------------- |
| `data`                   | array  | Array containing a single [User object](#user-object) |
| `pricing.creditsCharged` | number | Credits charged for this request                      |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate.

***

### Get User Posts

Returns posts published by an Instagram user. Use `cursor` to paginate or `maxItems` for a one-shot bulk pull (mutually exclusive).

**Request**

```http
GET /instagram/user/{id}/posts
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type            | Required | Default | Description                                                                    |
| ---------- | --------------- | -------- | ------- | ------------------------------------------------------------------------------ |
| `id`       | string (path)   | Yes      | —       | Numeric Instagram user ID, 1–100 characters                                    |
| `maxItems` | integer (query) | No       | —       | One-shot bulk pull, 1–200 results. Mutually exclusive with `cursor`            |
| `cursor`   | string (query)  | No       | —       | Pagination cursor from a previous response. Mutually exclusive with `maxItems` |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/user/25025320/posts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d maxItems=50
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "photo",
      "id": "3881985252256633854",
      "code": "CzABCdef123",
      "url": "https://www.instagram.com/p/CzABCdef123/",
      "caption": "Check out our latest update!",
      "createdAt": 1714560000,
      "likeCount": 12500,
      "commentCount": 320,
      "isAvailable": true,
      "isCarousel": false,
      "isVideo": false,
      "isPinned": false,
      "isPaidPartnership": false,
      "isLikeAndViewCountsDisabled": false,
      "owner": {
        "id": "25025320",
        "username": "instagram",
        "fullName": "Instagram",
        "profilePicUrl": "https://instagram.com/static/images/profile.jpg",
        "isVerified": true,
        "isPrivate": false
      },
      "coowners": [],
      "location": null,
      "image": {},
      "video": null,
      "audio": null,
      "carouselMedia": []
    }
  ],
  "pagination": { "page": null, "hasNextPage": true, "cursor": "QVFE...", "offset": null },
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                                   | Type              | Description                                    |
| --------------------------------------- | ----------------- | ---------------------------------------------- |
| `data`                                  | array             | Array of [Post objects](#post-object)          |
| `pagination.hasNextPage`                | boolean, nullable | Whether another page is available              |
| `pagination.cursor`                     | string, nullable  | Cursor to pass as `cursor` on the next request |
| `pagination.page` / `pagination.offset` | nullable          | Unused by this endpoint — always `null` here   |
| `pricing.creditsCharged`                | number            | Credits charged for this request               |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate — read the figure from each response.

***

### Get User Tagged Posts

Returns posts where the Instagram user is tagged. Use `cursor` to paginate or `maxItems` for a one-shot bulk pull (mutually exclusive).

**Request**

```http
GET /instagram/user/{id}/posts/tagged
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type            | Required | Default | Description                                                                    |
| ---------- | --------------- | -------- | ------- | ------------------------------------------------------------------------------ |
| `id`       | string (path)   | Yes      | —       | Numeric Instagram user ID, 1–100 characters                                    |
| `maxItems` | integer (query) | No       | —       | One-shot bulk pull, 1–200 results. Mutually exclusive with `cursor`            |
| `cursor`   | string (query)  | No       | —       | Pagination cursor from a previous response. Mutually exclusive with `maxItems` |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/user/25025320/posts/tagged" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d cursor="QVFE..."
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "photo",
      "id": "3881985252256633900",
      "code": "CzXYZdef456",
      "url": "https://www.instagram.com/p/CzXYZdef456/",
      "caption": "Great day at the launch event!",
      "createdAt": 1714646400,
      "likeCount": 4300,
      "commentCount": 95,
      "isAvailable": true,
      "isCarousel": false,
      "isVideo": false,
      "isPinned": false,
      "isPaidPartnership": false,
      "isLikeAndViewCountsDisabled": false,
      "owner": {
        "id": "7894561230",
        "username": "anotheruser",
        "fullName": "Another User",
        "profilePicUrl": "https://instagram.com/static/images/profile2.jpg",
        "isVerified": false,
        "isPrivate": false
      },
      "coowners": [],
      "location": null,
      "image": {},
      "video": null,
      "audio": null,
      "carouselMedia": []
    }
  ],
  "pagination": { "page": null, "hasNextPage": true, "cursor": "QVFE...", "offset": null },
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                                   | Type              | Description                                    |
| --------------------------------------- | ----------------- | ---------------------------------------------- |
| `data`                                  | array             | Array of [Post objects](#post-object)          |
| `pagination.hasNextPage`                | boolean, nullable | Whether another page is available              |
| `pagination.cursor`                     | string, nullable  | Cursor to pass as `cursor` on the next request |
| `pagination.page` / `pagination.offset` | nullable          | Unused by this endpoint — always `null` here   |
| `pricing.creditsCharged`                | number            | Credits charged for this request               |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate.

***

### Get User Reels

Returns reels published by an Instagram user. Use `cursor` to paginate or `maxItems` for a one-shot bulk pull (mutually exclusive). Reels are returned using the same [Post object](#post-object) schema as the posts endpoints — there is no separate "reel" schema.

**Request**

```http
GET /instagram/user/{id}/reels
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type            | Required | Default | Description                                                                    |
| ---------- | --------------- | -------- | ------- | ------------------------------------------------------------------------------ |
| `id`       | string (path)   | Yes      | —       | Numeric Instagram user ID, 1–100 characters                                    |
| `maxItems` | integer (query) | No       | —       | One-shot bulk pull, 1–200 results. Mutually exclusive with `cursor`            |
| `cursor`   | string (query)  | No       | —       | Pagination cursor from a previous response. Mutually exclusive with `maxItems` |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/user/25025320/reels" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d maxItems=25
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "reel",
      "id": "3881985252256634000",
      "code": "CzREELabc789",
      "url": "https://www.instagram.com/p/CzREELabc789/",
      "caption": "New reel just dropped 🎥",
      "createdAt": 1714732800,
      "likeCount": 98000,
      "commentCount": 1820,
      "isAvailable": true,
      "isCarousel": false,
      "isVideo": true,
      "isPinned": false,
      "isPaidPartnership": false,
      "isLikeAndViewCountsDisabled": false,
      "owner": {
        "id": "25025320",
        "username": "instagram",
        "fullName": "Instagram",
        "profilePicUrl": "https://instagram.com/static/images/profile.jpg",
        "isVerified": true,
        "isPrivate": false
      },
      "coowners": [],
      "location": null,
      "image": null,
      "video": {},
      "audio": {},
      "carouselMedia": []
    }
  ],
  "pagination": { "page": null, "hasNextPage": true, "cursor": "QVFE...", "offset": null },
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                                   | Type              | Description                                                          |
| --------------------------------------- | ----------------- | -------------------------------------------------------------------- |
| `data`                                  | array             | Array of [Post objects](#post-object) (returned with `type: "reel"`) |
| `pagination.hasNextPage`                | boolean, nullable | Whether another page is available                                    |
| `pagination.cursor`                     | string, nullable  | Cursor to pass as `cursor` on the next request                       |
| `pagination.page` / `pagination.offset` | nullable          | Unused by this endpoint — always `null` here                         |
| `pricing.creditsCharged`                | number            | Credits charged for this request                                     |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate.

***

### Get User Stories

Returns the user's currently-active Instagram stories. Not paginated — stories expire 24 hours after posting, so the full active set is always returned in one call.

**Request**

```http
GET /instagram/user/{id}/stories
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter | Type          | Required | Default | Description                                 |
| --------- | ------------- | -------- | ------- | ------------------------------------------- |
| `id`      | string (path) | Yes      | —       | Numeric Instagram user ID, 1–100 characters |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/user/25025320/stories" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "video",
      "id": "3245678901234567890",
      "code": "CzABCdef123",
      "createdAt": 1714560000,
      "expiringAt": 1714646400,
      "duration": 14.97,
      "hasAudio": true,
      "hasTranslation": false,
      "canReshare": true,
      "canReply": true,
      "isVideo": true,
      "owner": {
        "id": "25025320",
        "username": "instagram",
        "fullName": "Instagram",
        "profilePicUrl": "https://instagram.com/static/images/profile.jpg",
        "isVerified": true,
        "isPrivate": false
      },
      "coowners": [],
      "image": null,
      "video": {},
      "audio": {},
      "link": null,
      "comments": [],
      "mentions": [],
      "hashtags": []
    }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                    | Type   | Description                             |
| ------------------------ | ------ | --------------------------------------- |
| `data`                   | array  | Array of [Story objects](#story-object) |
| `pricing.creditsCharged` | number | Credits charged for this request        |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate.

***

### Get Post By Shortcode

Returns a single Instagram post by its shortcode (the segment after `/p/` in the post's URL).

**Request**

```http
GET /instagram/post/code/{code}
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter | Type          | Required | Default | Description                                                                                       |
| --------- | ------------- | -------- | ------- | ------------------------------------------------------------------------------------------------- |
| `code`    | string (path) | Yes      | —       | Post shortcode, 1–100 characters (e.g. `CzABCdef123`, the code in `instagram.com/p/CzABCdef123/`) |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/post/code/CzABCdef123" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "photo",
      "id": "3881985252256633854",
      "code": "CzABCdef123",
      "url": "https://www.instagram.com/p/CzABCdef123/",
      "caption": "Check out our latest update!",
      "createdAt": 1714560000,
      "likeCount": 12500,
      "commentCount": 320,
      "isAvailable": true,
      "isCarousel": false,
      "isVideo": false,
      "isPinned": false,
      "isPaidPartnership": false,
      "isLikeAndViewCountsDisabled": false,
      "owner": {
        "id": "25025320",
        "username": "instagram",
        "fullName": "Instagram",
        "profilePicUrl": "https://instagram.com/static/images/profile.jpg",
        "isVerified": true,
        "isPrivate": false
      },
      "coowners": [],
      "location": null,
      "image": {},
      "video": null,
      "audio": null,
      "carouselMedia": []
    }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                    | Type   | Description                                           |
| ------------------------ | ------ | ----------------------------------------------------- |
| `data`                   | array  | Array containing a single [Post object](#post-object) |
| `pricing.creditsCharged` | number | Credits charged for this request                      |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate.

***

### Get Post Comments

Returns comments on an Instagram post. Use `cursor` to paginate or `maxItems` for a one-shot bulk pull (mutually exclusive). Takes the post's internal numeric `id`, **not** its shortcode.

**Request**

```http
GET /instagram/post/{id}/comments
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type            | Required | Default | Description                                                                    |
| ---------- | --------------- | -------- | ------- | ------------------------------------------------------------------------------ |
| `id`       | string (path)   | Yes      | —       | Numeric Instagram post ID, 1–100 characters (not the post's shortcode)         |
| `maxItems` | integer (query) | No       | —       | One-shot bulk pull, 1–500 results. Mutually exclusive with `cursor`            |
| `cursor`   | string (query)  | No       | —       | Pagination cursor from a previous response. Mutually exclusive with `maxItems` |

**Example**

```bash
curl -G "https://api.pullbay.com/instagram/post/3881985252256633854/comments" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d maxItems=100
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "type": "comment",
      "id": "18470084392099954",
      "userId": "53847071613",
      "message": "Love this!",
      "createdAt": "2026-05-05T19:46:32.000Z",
      "likeCount": 27,
      "replyCount": 0,
      "isRanked": false,
      "user": {
        "id": "53847071613",
        "username": "someuser",
        "fullName": "Some User",
        "profilePicUrl": "https://instagram.com/static/images/profile3.jpg",
        "isPrivate": false,
        "isVerified": false
      }
    }
  ],
  "pagination": { "page": null, "hasNextPage": true, "cursor": "QVFE...", "offset": null },
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                                   | Type              | Description                                    |
| --------------------------------------- | ----------------- | ---------------------------------------------- |
| `data`                                  | array             | Array of [Comment objects](#comment-object)    |
| `pagination.hasNextPage`                | boolean, nullable | Whether another page is available              |
| `pagination.cursor`                     | string, nullable  | Cursor to pass as `cursor` on the next request |
| `pagination.page` / `pagination.offset` | nullable          | Unused by this endpoint — always `null` here   |
| `pricing.creditsCharged`                | number            | Credits charged for this request               |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No published flat rate.

## Errors

All non-2xx responses share the same envelope:

```json
{
  "status": 400,
  "message": "Bad request",
  "success": false,
  "error": { "code": "BAD_REQUEST" }
}
```

| Status | Meaning                                  |
| ------ | ---------------------------------------- |
| `400`  | Bad request — missing/invalid parameters |
| `402`  | Insufficient credits                     |
| `404`  | User, post, or story not found           |

## Object Schema

### User ID lookup object

| Field         | Type    | Description                                                          |
| ------------- | ------- | -------------------------------------------------------------------- |
| `isAvailable` | boolean | Whether the handle exists/is in use                                  |
| `handle`      | string  | The handle that was looked up                                        |
| `id`          | string  | Numeric Instagram user ID. Present only when `isAvailable` is `true` |

### User object

| Field             | Type             | Description                               |
| ----------------- | ---------------- | ----------------------------------------- |
| `type`            | string           | Always `user`                             |
| `isAvailable`     | boolean          | Whether the profile is available          |
| `id`              | string           | Numeric Instagram user ID                 |
| `username`        | string           | Handle, without `@`                       |
| `fullName`        | string           | Display name                              |
| `biography`       | string           | Bio text                                  |
| `profilePicUrl`   | string           | Profile picture URL                       |
| `website`         | string           | Link in bio                               |
| `category`        | string           | Business/category label (e.g. `App page`) |
| `cityName`        | string, nullable | City shown on profile                     |
| `isPrivate`       | boolean          | Whether the account is private            |
| `isVerified`      | boolean          | Whether the account has a verified badge  |
| `isBusiness`      | boolean          | Whether the account is a business account |
| `hasVideos`       | boolean          | Whether the account has published videos  |
| `hasGuides`       | boolean          | Whether the account has published guides  |
| `postCount`       | integer          | Total post count                          |
| `followerCount`   | integer          | Follower count                            |
| `followingCount`  | integer          | Following count                           |
| `totalReelsCount` | integer          | Total reel count                          |
| `bioLinks`        | array            | Links shown in the bio                    |

### Post owner object

Lightweight user reference embedded in posts and stories.

| Field           | Type    | Description                              |
| --------------- | ------- | ---------------------------------------- |
| `id`            | string  | Numeric Instagram user ID                |
| `username`      | string  | Handle, without `@`                      |
| `fullName`      | string  | Display name                             |
| `profilePicUrl` | string  | Profile picture URL                      |
| `isVerified`    | boolean | Whether the account has a verified badge |
| `isPrivate`     | boolean | Whether the account is private           |

### Post object

Used for posts, tagged posts, and reels — reels are returned with `type: "reel"` but share this same schema; there is no separate reel object.

| Field                         | Type             | Description                                                                     |
| ----------------------------- | ---------------- | ------------------------------------------------------------------------------- |
| `type`                        | string           | `photo` / `video` / `carousel` / `reel`                                         |
| `id`                          | string           | Numeric post ID                                                                 |
| `code`                        | string           | Shortcode (the segment after `/p/` in the URL)                                  |
| `url`                         | string           | Permalink to the post                                                           |
| `caption`                     | string           | Caption text                                                                    |
| `createdAt`                   | integer          | Unix timestamp (seconds) the post was published                                 |
| `likeCount`                   | integer          | Like count                                                                      |
| `commentCount`                | integer          | Comment count                                                                   |
| `isAvailable`                 | boolean          | Whether the post is still available                                             |
| `isCarousel`                  | boolean          | Whether the post is a multi-media carousel                                      |
| `isVideo`                     | boolean          | Whether the post is a video                                                     |
| `isPinned`                    | boolean          | Whether the post is pinned to the profile                                       |
| `isPaidPartnership`           | boolean          | Whether the post is a paid partnership                                          |
| `isLikeAndViewCountsDisabled` | boolean          | Whether like/view counts are hidden                                             |
| `owner`                       | object           | [Post owner object](#post-owner-object)                                         |
| `coowners`                    | array            | Additional tagged collaborators, each a [post owner object](#post-owner-object) |
| `location`                    | object, nullable | Tagged location                                                                 |
| `image`                       | object, nullable | Image media data                                                                |
| `video`                       | object, nullable | Video media data                                                                |
| `audio`                       | object, nullable | Audio track data                                                                |
| `carouselMedia`               | array            | Per-slide media for carousel posts                                              |

### Comment object

| Field        | Type               | Description                                                                                    |
| ------------ | ------------------ | ---------------------------------------------------------------------------------------------- |
| `type`       | string             | Always `comment`                                                                               |
| `id`         | string             | Comment ID                                                                                     |
| `userId`     | string             | Numeric ID of the commenter                                                                    |
| `message`    | string             | Comment text                                                                                   |
| `createdAt`  | string (date-time) | When the comment was posted                                                                    |
| `likeCount`  | integer            | Like count                                                                                     |
| `replyCount` | integer            | Reply count                                                                                    |
| `isRanked`   | boolean            | Whether the comment is algorithmically ranked/pinned                                           |
| `user`       | object             | Commenter reference (`id`, `username`, `fullName`, `profilePicUrl`, `isPrivate`, `isVerified`) |

### Story object

| Field            | Type             | Description                                                                     |
| ---------------- | ---------------- | ------------------------------------------------------------------------------- |
| `type`           | string           | `photo` / `video`                                                               |
| `id`             | string           | Story ID                                                                        |
| `code`           | string           | Shortcode                                                                       |
| `createdAt`      | integer          | Unix timestamp (seconds) the story was posted                                   |
| `expiringAt`     | integer          | Unix timestamp (seconds) the story expires                                      |
| `duration`       | number           | Duration in seconds                                                             |
| `hasAudio`       | boolean          | Whether the story has audio                                                     |
| `hasTranslation` | boolean          | Whether translated text is available                                            |
| `canReshare`     | boolean          | Whether the story can be reshared                                               |
| `canReply`       | boolean          | Whether replies are allowed                                                     |
| `isVideo`        | boolean          | Whether the story is a video                                                    |
| `owner`          | object           | [Post owner object](#post-owner-object)                                         |
| `coowners`       | array            | Additional tagged collaborators, each a [post owner object](#post-owner-object) |
| `image`          | object, nullable | Image media data                                                                |
| `video`          | object, nullable | Video media data                                                                |
| `audio`          | object, nullable | Audio track data                                                                |
| `link`           | object, nullable | Attached link sticker data                                                      |
| `comments`       | array            | Comments left on the story                                                      |
| `mentions`       | array            | Mentioned accounts                                                              |
| `hashtags`       | array            | Tagged hashtags                                                                 |

## Finding User IDs and Handles

This service uses three distinct identifiers — keep them separate:

* **`handle`**: the `@username` shown on a profile, passed without the `@` (e.g. `instagram` for `@instagram`). Used only by `GET /instagram/userid/{handle}` and `GET /instagram/user/handle/{handle}`.
* **`id`**: Instagram's internal numeric ID for a user, post, or comment. Required by every other endpoint in this service (posts, tagged posts, reels, stories, and post comments all key off a numeric `id`, not a handle or shortcode).
* **`code`**: a post's shortcode — the segment after `/p/` in a post's URL (e.g. `CzABCdef123` in `https://www.instagram.com/p/CzABCdef123/`). Used only by `GET /instagram/post/code/{code}`.

{% stepper %}
{% step %}

### If you only have a handle and need a numeric user `id`

Call `GET /instagram/userid/{handle}` to resolve the handle and confirm `isAvailable` is `true`. The response's `id` field is the numeric user ID.
{% endstep %}

{% step %}

### Use that `id` for the user endpoints

Use that `id` for the posts, tagged posts, reels, and stories endpoints (`/instagram/user/{id}/...`).
{% endstep %}
{% endstepper %}

If you need the full profile anyway, `GET /instagram/user/handle/{handle}` returns both the profile and the numeric `id` in a single call, saving a round trip.

A post's `id` (needed for the comments endpoint) is not the same as its `code` (shortcode). If you only have a post's shortcode, call `GET /instagram/post/code/{code}` first — the response's `id` field is the numeric post ID to use with `GET /instagram/post/{id}/comments`.

## Python Example

This example resolves a handle to a user ID, then paginates through that user's posts using `cursor`:

```python
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.pullbay.com"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

def resolve_handle(handle):
    resp = requests.get(f"{BASE_URL}/instagram/userid/{handle}", headers=HEADERS)
    resp.raise_for_status()
    body = resp.json()
    lookup = body["data"][0]
    if not lookup["isAvailable"]:
        raise ValueError(f"Handle '{handle}' is not available")
    return lookup["id"]

def get_all_posts(user_id, max_pages=10):
    all_posts = []
    cursor = None
    for _ in range(max_pages):
        params = {"cursor": cursor} if cursor else {}
        resp = requests.get(
            f"{BASE_URL}/instagram/user/{user_id}/posts",
            headers=HEADERS,
            params=params,
        )
        resp.raise_for_status()
        body = resp.json()
        all_posts.extend(body["data"])
        pagination = body.get("pagination", {})
        if not pagination.get("hasNextPage"):
            break
        cursor = pagination.get("cursor")
    return all_posts

user_id = resolve_handle("instagram")
posts = get_all_posts(user_id)
print(f"Fetched {len(posts)} posts for user {user_id}")
```

Each request is billed independently, with the charged amount reported in that response's `pricing.creditsCharged` — there's no separate "fetch everything in one call" endpoint, so a multi-page pull like this makes one request per page.

## FAQ

<details>

<summary>What's the difference between <code>handle</code>, <code>id</code>, and <code>code</code>?</summary>

`handle` is the `@username` (without the `@`), used only to resolve or look up a profile. `id` is Instagram's internal numeric identifier for a user, post, or comment, and is required by every other endpoint. `code` is a post's shortcode from its URL, used only to fetch a post by `GET /instagram/post/code/{code}`. They are not interchangeable — passing a handle where an `id` is expected (or vice versa) will not resolve.

</details>

<details>

<summary>How do I get a numeric user ID if I only have a handle?</summary>

Call `GET /instagram/userid/{handle}` and read the `id` field from the response, or call `GET /instagram/user/handle/{handle}` if you also want the full profile in the same request.

</details>

<details>

<summary>How do I get a post's numeric ID if I only have its shortcode?</summary>

Call `GET /instagram/post/code/{code}`. The returned [Post object](#post-object) includes the post's numeric `id`, which you then use with `GET /instagram/post/{id}/comments`.

</details>

<details>

<summary>Are reels returned with a different schema than posts?</summary>

No. Reels use the same [Post object](#post-object) schema as regular posts and tagged posts; the `type` field is set to `reel` (or `video`) to distinguish them.

</details>

<details>

<summary>Why don't stories support pagination?</summary>

Instagram stories expire 24 hours after posting, so the active set is always small enough to return in a single call. There is no `cursor` or `maxItems` parameter on the stories endpoint.

</details>

<details>

<summary>What's the credit cost per request?</summary>

It's dynamic — every response includes `pricing.creditsCharged` with the exact amount for that call. There's no fixed published rate per endpoint or per result.

</details>

## Next Steps

* [**API Integration Guide**](broken://pages/68e75ab1a73d266350bd68301be87ff97cad563e) — integrate the Pullbay API into your backend application.
* [**n8n Integration Guide**](broken://pages/4308164455b56bbc694cf74c9768ea689c2fe719) — set up automated workflows using n8n with no coding required.
* [**Services Overview**](broken://pages/0d55376cbcca70097a683a71a593d3077825dbf1) — explore all available Pullbay services.
