> 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/appstore.md).

# Appstore

The Pullbay App Store API provides programmatic access to iOS app metadata, search, similar-app recommendations, reviews, and developer catalogs from the Apple App Store. Integrate App Store data into your applications, dashboards, and analytics pipelines without scraping or manual lookups.

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

## Overview

The App Store service lets you:

* Look up a single app by its numeric App ID or its Bundle ID
* Search the App Store by keyword
* Find apps similar to a given app
* Fetch reviews for an app, sorted by recency or helpfulness
* List every app published by a given developer

All endpoints are read-only `GET` requests against public App Store data — you don't need to own or register an app of your own.

## Common Use Cases

**Competitor Analysis** — Pull a competitor's app metadata and reviews to track positioning, version cadence, and rating trends over time.

**Sentiment Monitoring** — Collect reviews on a schedule and feed the `title`/`text` fields into your own sentiment-analysis or alerting pipeline.

**Market Research** — Use Search Apps and Get Similar Apps together to map out a category and see how apps cluster around features and audiences.

**Product Development** — Mine review text for recurring feature requests and complaints to help prioritize a roadmap.

**Developer Portfolio Tracking** — Use Get Developer Apps to see everything a given publisher has shipped, useful for due diligence or competitive landscape work.

## Endpoints

| Endpoint                  | Description                             | Pagination          |
| ------------------------- | --------------------------------------- | ------------------- |
| `GET /appstore/apps`      | Get a single app by App ID or Bundle ID | —                   |
| `GET /appstore/search`    | Search apps by term                     | `page` / `maxItems` |
| `GET /appstore/similar`   | Get apps similar to a given app         | —                   |
| `GET /appstore/reviews`   | Get reviews for an app                  | `page` / `maxItems` |
| `GET /appstore/developer` | Get all apps published by a developer   | —                   |

***

### Get App

Returns a single application. Provide exactly one of `appId` or `bundleId`.

**Request**

```bash
GET /appstore/apps
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type   | Required                  | Default | Description                                                                                       |
| ---------- | ------ | ------------------------- | ------- | ------------------------------------------------------------------------------------------------- |
| `appId`    | string | One of `appId`/`bundleId` | —       | Numeric App Store ID, 8–12 digits (e.g. `389801252`)                                              |
| `bundleId` | string | One of `appId`/`bundleId` | —       | Bundle identifier, up to 255 characters (e.g. `com.burbn.instagram`)                              |
| `country`  | string | No                        | —       | 2-letter storefront code. Not restricted to a fixed list — any 2-letter code is accepted.         |
| `lang`     | string | No                        | —       | Language code for localized text, 2–3 letters with an optional region subtag (e.g. `en`, `en-us`) |

**Example**

```bash
curl -G "https://api.pullbay.com/appstore/apps" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d appId=389801252 \
  -d country=us
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "id": 389801252,
      "appId": "com.burbn.instagram",
      "title": "Instagram",
      "url": "https://apps.apple.com/us/app/instagram/id389801252?uo=4",
      "description": "Little moments lead to big friendships. Share yours on Instagram.",
      "icon": "https://is1-ssl.mzstatic.com/.../512x512bb.jpg",
      "genres": ["Photo & Video", "Social Networking"],
      "genreIds": ["6008", "6005"],
      "primaryGenre": "Photo & Video",
      "primaryGenreId": 6008,
      "contentRating": "12+",
      "languages": ["EN", "FR", "DE", "JA", "ES"],
      "size": "563586048",
      "requiredOsVersion": "16.3",
      "released": "2010-10-06T08:12:41Z",
      "updated": "2026-04-20T17:48:35Z",
      "releaseNotes": "Performance optimizations and stability improvements.",
      "version": "426.0.0",
      "price": 0,
      "currency": "USD",
      "free": true,
      "developerId": 389801255,
      "developer": "Instagram, Inc.",
      "developerUrl": "https://apps.apple.com/us/developer/instagram-inc/id389801255?uo=4",
      "developerWebsite": "http://instagram.com/",
      "score": 4.69066,
      "reviews": 28962365,
      "currentVersionScore": 4.69066,
      "currentVersionReviews": 28962365,
      "screenshots": ["https://is1-ssl.mzstatic.com/.../392x696bb.jpg"],
      "ipadScreenshots": [],
      "appletvScreenshots": [],
      "supportedDevices": ["iPhone5s-iPhone5s", "iPadAir-iPadAir", "iPhone16Pro-iPhone16Pro"]
    }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

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

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

***

### Search Apps

Search the App Store for apps matching a term.

**Request**

```bash
GET /appstore/search
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type    | Required | Default | Description                                                       |
| ---------- | ------- | -------- | ------- | ----------------------------------------------------------------- |
| `term`     | string  | Yes      | —       | Search term, 1–255 characters                                     |
| `country`  | string  | No       | —       | 2-letter storefront code                                          |
| `lang`     | string  | No       | —       | Language code for localized text                                  |
| `page`     | integer | No       | —       | Page number, 1–5. Mutually exclusive with `maxItems`              |
| `maxItems` | integer | No       | —       | One-shot bulk pull, 1–200 results. Mutually exclusive with `page` |

**Example**

```bash
curl -G "https://api.pullbay.com/appstore/search" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d term="photo editor" \
  -d country=us \
  -d page=1
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    { "id": 389801252, "appId": "com.burbn.instagram", "title": "Instagram", "...": "..." }
  ],
  "pagination": { "page": 1, "hasNextPage": true, "cursor": null, "offset": null },
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                                     | Type              | Description                                         |
| ----------------------------------------- | ----------------- | --------------------------------------------------- |
| `data`                                    | array             | Array of [Application objects](#application-object) |
| `pagination.page`                         | integer, nullable | Current page number (only set when using `page`)    |
| `pagination.hasNextPage`                  | boolean, nullable | Whether another page is available                   |
| `pagination.cursor` / `pagination.offset` | string, nullable  | Unused by this endpoint — always `null` here        |
| `pricing.creditsCharged`                  | number            | Credits charged for this request                    |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No flat per-page or per-result rate is published — read the figure from each response.

***

### Get Similar Apps

Returns apps similar to a given app. Provide exactly one of `appId` or `bundleId`.

**Request**

```bash
GET /appstore/similar
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type   | Required                  | Default | Description                       |
| ---------- | ------ | ------------------------- | ------- | --------------------------------- |
| `appId`    | string | One of `appId`/`bundleId` | —       | Numeric App Store ID, 8–12 digits |
| `bundleId` | string | One of `appId`/`bundleId` | —       | Bundle identifier                 |
| `country`  | string | No                        | —       | 2-letter storefront code          |
| `lang`     | string | No                        | —       | Language code for localized text  |

**Example**

```bash
curl -G "https://api.pullbay.com/appstore/similar" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d bundleId=com.burbn.instagram
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    { "id": 454638411, "appId": "com.toyopagroup.picaboo", "title": "Snapchat", "...": "..." }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

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

**Credit cost:** dynamic, returned in `pricing.creditsCharged`.

***

### Get Reviews

Returns reviews for one app. Provide exactly one of `appId` or `bundleId`.

**Request**

```bash
GET /appstore/reviews
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter  | Type    | Required                  | Default | Description                                                       |
| ---------- | ------- | ------------------------- | ------- | ----------------------------------------------------------------- |
| `appId`    | string  | One of `appId`/`bundleId` | —       | Numeric App Store ID, 8–12 digits                                 |
| `bundleId` | string  | One of `appId`/`bundleId` | —       | Bundle identifier                                                 |
| `country`  | string  | No                        | —       | 2-letter storefront code                                          |
| `sort`     | string  | No                        | —       | `recent` or `helpful`                                             |
| `page`     | integer | No                        | —       | Page number, 1–10. Mutually exclusive with `maxItems`             |
| `maxItems` | integer | No                        | —       | One-shot bulk pull, 1–500 results. Mutually exclusive with `page` |

**Example**

```bash
curl -G "https://api.pullbay.com/appstore/reviews" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d appId=389801252 \
  -d country=us \
  -d sort=recent \
  -d page=1
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "id": "13997548250",
      "date": "2026-04-25T19:57:33-07:00",
      "userName": "Catie0012",
      "userUrl": "https://itunes.apple.com/us/reviews/id1632846422",
      "version": "426.0.0",
      "score": 5,
      "title": "How I love your app",
      "text": "Una experiencia inigualable",
      "url": "https://itunes.apple.com/us/review?id=389801252&type=Purple%20Software",
      "country": "US"
    }
  ],
  "pagination": { "page": 1, "hasNextPage": true, "cursor": null, "offset": null },
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

| Field                    | Type              | Description                                      |
| ------------------------ | ----------------- | ------------------------------------------------ |
| `data`                   | array             | Array of [Review objects](#review-object)        |
| `pagination.page`        | integer, nullable | Current page number (only set when using `page`) |
| `pagination.hasNextPage` | boolean, nullable | Whether another page is available                |
| `pricing.creditsCharged` | number            | Credits charged for this request                 |

**Credit cost:** dynamic, returned in `pricing.creditsCharged`. No flat per-page or per-review rate is published.

***

### Get Developer Apps

Returns the list of apps published by a single developer.

**Request**

```bash
GET /appstore/developer
Authorization: Bearer YOUR_API_KEY
```

**Parameters**

| Parameter     | Type   | Required | Default | Description                       |
| ------------- | ------ | -------- | ------- | --------------------------------- |
| `developerId` | string | Yes      | —       | Numeric developer ID, 8–12 digits |
| `country`     | string | No       | —       | 2-letter storefront code          |

**Example**

```bash
curl -G "https://api.pullbay.com/appstore/developer" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d developerId=389801255
```

**Response**

```json
{
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    { "id": 389801252, "appId": "com.burbn.instagram", "title": "Instagram", "...": "..." }
  ],
  "pricing": { "creditsCharged": 1 }
}
```

**Response Schema**

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

**Credit cost:** dynamic, returned in `pricing.creditsCharged`.

***

## 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, or both `appId` and `bundleId` supplied |
| `402`  | Insufficient credits                                                              |
| `404`  | App, developer, or review set not found                                           |

## Object Schema

### Application object

| Field                                                    | Type                      | Description                                     |
| -------------------------------------------------------- | ------------------------- | ----------------------------------------------- |
| `id`                                                     | integer                   | Numeric App Store ID                            |
| `appId`                                                  | string                    | Bundle identifier                               |
| `title`                                                  | string                    | App name                                        |
| `url`                                                    | string                    | App Store listing URL                           |
| `description`                                            | string                    | App description                                 |
| `icon`                                                   | string                    | Icon image URL                                  |
| `genres` / `genreIds`                                    | array                     | Genre names and IDs                             |
| `primaryGenre` / `primaryGenreId`                        | string / integer          | Primary genre name and ID                       |
| `contentRating`                                          | string                    | Age rating (e.g. `12+`)                         |
| `languages`                                              | array                     | Supported language codes                        |
| `size`                                                   | string                    | App size in bytes                               |
| `requiredOsVersion`                                      | string                    | Minimum iOS version                             |
| `released` / `updated`                                   | string (date-time)        | Initial release and last update timestamps      |
| `releaseNotes`                                           | string                    | "What's New" text for the current version       |
| `version`                                                | string                    | Current version number                          |
| `price` / `currency` / `free`                            | number / string / boolean | Pricing info                                    |
| `developerId` / `developer`                              | integer / string          | Developer ID and name                           |
| `developerUrl` / `developerWebsite`                      | string                    | Developer's App Store page and external site    |
| `score` / `reviews`                                      | number / integer          | All-time rating and review count                |
| `currentVersionScore` / `currentVersionReviews`          | number / integer          | Rating and review count for the current version |
| `screenshots` / `ipadScreenshots` / `appletvScreenshots` | array                     | Screenshot URLs per device class                |
| `supportedDevices`                                       | array                     | Compatible device identifiers                   |

### Review object

| Field      | Type               | Description                                 |
| ---------- | ------------------ | ------------------------------------------- |
| `id`       | string             | Review ID                                   |
| `date`     | string (date-time) | When the review was posted                  |
| `userName` | string             | Reviewer's display name                     |
| `userUrl`  | string             | Link to the reviewer's profile              |
| `version`  | string             | App version the review was left for         |
| `score`    | integer            | Rating, 1–5                                 |
| `title`    | string             | Review title                                |
| `text`     | string             | Review body                                 |
| `url`      | string             | Permalink to the review                     |
| `country`  | string             | Storefront country the review was posted on |

Note: the Review object does not include a helpful-vote count or "verified purchase" flag — only the fields listed above are returned.

## Finding App IDs and Bundle IDs

* **App ID**: the numeric ID in an App Store URL, e.g. `https://apps.apple.com/us/app/instagram/id389801252` → `389801252`.
* **Bundle ID**: the package identifier shown on a developer's site or in App Store Connect, e.g. `com.burbn.instagram`.
* Either ID resolves the same app — use whichever you already have on hand. Don't pass both in the same request.

## Country and Language Codes

* `country` accepts any 2-letter code (the schema only constrains it to exactly 2 characters) — it isn't validated against a fixed allow-list in the spec, so pass a standard ISO 3166-1 alpha-2 storefront code (`us`, `gb`, `jp`, `de`, ...).
* `lang` accepts a 2–3 letter language code, optionally with a region subtag (`en`, `en-us`, `pt-br`) — also not restricted to a fixed list.
* Neither parameter has a documented default in the API spec. If you omit them, behavior is determined by the underlying App Store lookup rather than a guaranteed Pullbay default — pass both explicitly if you need a predictable storefront/locale.

## Python Example: Paginating Through Reviews

This example fetches reviews for an app a page at a time, stopping when `pagination.hasNextPage` is `false` or the page cap (10) is reached:

```python
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.pullbay.com"

def get_all_reviews(app_id, country="us", max_pages=10):
    all_reviews = []
    page = 1
    while page <= max_pages:
        resp = requests.get(
            f"{BASE_URL}/appstore/reviews",
            headers={"Authorization": f"Bearer {API_KEY}"},
            params={"appId": app_id, "country": country, "sort": "recent", "page": page},
        )
        resp.raise_for_status()
        body = resp.json()
        all_reviews.extend(body["data"])
        if not body.get("pagination", {}).get("hasNextPage"):
            break
        page += 1
    return all_reviews

reviews = get_all_reviews(389801252)
print(f"Fetched {len(reviews)} reviews")
```

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>How do I find an app's ID?</summary>

Visit the app's page on the Apple App Store. Look at the URL — it contains `/id` followed by a number. That number is the `appId`. For example, `https://apps.apple.com/us/app/instagram/id389801252` → `389801252`.

</details>

<details>

<summary>What countries are supported?</summary>

Any 2-letter storefront code is accepted by the API — it isn't restricted to a published list of supported countries.

</details>

<details>

<summary>How many reviews can I fetch in one call?</summary>

Up to 500 with `maxItems`, or up to 10 pages via `page` (page size isn't fixed by the spec). `page` and `maxItems` are mutually exclusive — use one or the other per request.

</details>

<details>

<summary>Can I filter reviews by star rating?</summary>

The API only supports sorting (`recent` or `helpful`), not server-side filtering by rating. Fetch the reviews you need and filter client-side on the `score` field.

</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>

<details>

<summary>Can I export reviews to CSV?</summary>

The API returns JSON. Convert it to CSV with your language's tooling (e.g. Python's `csv` module) or load it directly into a BI tool.

</details>
