> 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/getting-started/quickstart.md).

# Quickstart

Get up and running with the Pullbay API in minutes. This guide covers account setup, API key generation, and your first request — using the patterns that apply to every endpoint across every service.

***

## What Pullbay Provides

Pullbay is a data API platform. One API key, one request format, and one response envelope give you access to data from:

| Service           | Endpoints                                                            |
| ----------------- | -------------------------------------------------------------------- |
| **App Store**     | reviews, app details, search, similar apps, developer apps           |
| **Google Play**   | reviews, app details, search, similar apps, permissions, data safety |
| **YouTube**       | search, channel, comments, shorts, hashtags                          |
| **Twitter / X**   | user, handle, tweet, search                                          |
| **Instagram**     | user, posts, reels, stories, tagged posts, post comments             |
| **TikTok**        | user, post, post comments, hashtag, search                           |
| **Reddit**        | subreddit, posts, post comments, user, user posts, search            |
| **Google Search** | search                                                               |
| **Google News**   | search, category                                                     |
| **Google Maps**   | place search, place details, reviews                                 |
| **DuckDuckGo**    | search, images, news, videos                                         |
| **Yelp**          | place search, place details, reviews                                 |
| **Apartments**    | property search, property details, images, reviews                   |

All endpoints share the same authentication method, request structure, response envelope, and error format. Learn it once, use it everywhere.

***

{% stepper %}
{% step %}

## Create Your Account

1. Visit [dashboard.pullbay.com](https://dashboard.pullbay.com/)
2. Click **Sign Up**, enter your email, and verify your address (or sign in with Google)
3. Your account is active with free credits — no credit card required
   {% endstep %}

{% step %}

## Get Your API Key

1. Sign in to your [dashboard](https://dashboard.pullbay.com/)
2. Navigate to **API Keys** in the left sidebar
3. Click **Create New Key**, give it a name (e.g. "Development"), and click **Create**
4. Copy the key — it is shown only once

Store the key in an environment variable. Never commit it to version control.

```bash
# .env
PULLBAY_API_KEY=your_key_here
```

{% endstep %}

{% step %}

## Make Your First Request

Every Pullbay endpoint follows the same URL pattern:

```
GET https://api.pullbay.com/{service}/{endpoint}
```

Authentication is always the same Bearer header:

```
Authorization: Bearer YOUR_API_KEY
```

Here's a concrete first request — fetching App Store reviews. The same pattern works for every other service and endpoint.

{% tabs %}
{% tab title="cURL" %}

```bash
curl "https://api.pullbay.com/appstore/reviews?appId=284882215&maxItems=5" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.get(
    "https://api.pullbay.com/appstore/reviews",
    params={"appId": "284882215", "maxItems": 5},
    headers={"Authorization": f"Bearer {os.environ['PULLBAY_API_KEY']}"},
    timeout=30,
)
print(response.json())
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const response = await fetch(
  'https://api.pullbay.com/appstore/reviews?appId=284882215&maxItems=5',
  { headers: { 'Authorization': `Bearer ${process.env.PULLBAY_API_KEY}` } }
);
const data = await response.json();
console.log(data);
```

{% endtab %}
{% endtabs %}

The same structure — `GET`, `Authorization` header, query parameters — applies to every other endpoint:

```bash
# YouTube channel search
curl "https://api.pullbay.com/youtube/search?query=openai&maxItems=5" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Google Play reviews
curl "https://api.pullbay.com/google-play/reviews?appId=com.instagram.android&maxItems=5" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Google Search
curl "https://api.pullbay.com/google-search/search?query=best+coffee+shops&maxItems=5" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

{% endstep %}

{% step %}

## Understand the Response

Every Pullbay endpoint returns the same envelope regardless of service:

```json
{
  "requestId": "3b8dcb68-1f8c-4a7b-b9e7-63a7b9986f24",
  "status": 200,
  "message": "OK",
  "success": true,
  "data": [
    {
      "id": "13997548250",
      "score": 5,
      "title": "Great app!",
      "text": "This app has changed how I work...",
      "userName": "HappyUser123",
      "date": "2026-01-15T10:30:00-07:00",
      "version": "5.2.1",
      "country": "US",
      "url": "https://itunes.apple.com/us/review?id=284882215"
    }
  ],
  "pagination": {
    "page": 1,
    "hasNextPage": true,
    "cursor": null,
    "offset": null
  },
  "pricing": {
    "creditsCharged": 5
  }
}
```

| Field                    | Description                                                                   |
| ------------------------ | ----------------------------------------------------------------------------- |
| `requestId`              | Unique request ID — log this for every call; required when contacting support |
| `success`                | `true` on success, `false` on error                                           |
| `data`                   | Array of result objects — field names vary by endpoint                        |
| `pagination.hasNextPage` | Whether more pages exist (only relevant in page mode)                         |
| `pagination.page`        | Current page number (only relevant in page mode)                              |
| `pricing.creditsCharged` | Credits consumed — charged per item returned                                  |

**The `data` fields vary by endpoint** (reviews have `score`, `text`; YouTube results have `title`, `viewCount`, etc.), but the envelope and all other top-level fields are always identical.

Always log `requestId` and `pricing.creditsCharged`:

```python
body = response.json()
print(f"requestId: {body['requestId']}, credits: {body['pricing']['creditsCharged']}")
```

{% endstep %}

{% step %}

## Handle Errors

Errors use the same envelope with `success: false`:

```json
{
  "requestId": "3b8dcb68-1f8c-4a7b-b9e7-63a7b9986f24",
  "status": 400,
  "message": "Validation failed",
  "success": false,
  "error": { "code": "VALIDATION_ERROR" }
}
```

| Status | Code                          | Cause                                  |
| ------ | ----------------------------- | -------------------------------------- |
| `400`  | `VALIDATION_ERROR`            | Invalid parameter name or value        |
| `401`  | `AUTHENTICATION_UNAUTHORIZED` | Missing or invalid API key             |
| `402`  | `TEAM_INSUFFICIENT_CREDITS`   | Credit balance is 0                    |
| `429`  | `RATE_LIMIT_EXCEEDED`         | Request rate exceeded for your plan    |
| `5xx`  | —                             | Server-side error — retry with backoff |

Failed requests do not consume credits.

```python
response = requests.get(url, params=params, headers=headers, timeout=30)

if not response.ok:
    body = response.json()
    print(f"Error {body['status']}: {body['error']['code']}")
    print(f"requestId: {body['requestId']}")
else:
    body = response.json()
    # process body["data"]
```

{% endstep %}

{% step %}

## Paginate Results

All paginated endpoints use the same two fetch modes — choose one per request:

{% tabs %}
{% tab title="Bulk fetch (`maxItems`)" %}
Get up to the endpoint maximum in one call:

```python
body = requests.get(
    "https://api.pullbay.com/appstore/reviews",
    params={"appId": "284882215", "maxItems": 500},
    headers={"Authorization": f"Bearer {os.environ['PULLBAY_API_KEY']}"},
    timeout=120,
).json()

print(f"{len(body['data'])} results — {body['pricing']['creditsCharged']} credits")
```

{% endtab %}

{% tab title="Page-by-page (`page`)" %}
Iterate one page at a time:

```python
all_results = []
page = 1

while True:
    body = requests.get(
        "https://api.pullbay.com/appstore/reviews",
        params={"appId": "284882215", "page": page},
        headers={"Authorization": f"Bearer {os.environ['PULLBAY_API_KEY']}"},
        timeout=30,
    ).json()

    all_results.extend(body["data"])

    if not body["pagination"]["hasNextPage"]:
        break
    page += 1
```

{% endtab %}
{% endtabs %}

`maxItems` and `page` are mutually exclusive — use one or the other, never both.
{% endstep %}
{% endstepper %}

***

## Check Your Usage

In your [dashboard](https://dashboard.pullbay.com/) → **Usage**:

* Credits remaining in your account
* Requests broken down by endpoint and date
* Rate limit status

***

## What's Next?

* **Authentication Guide** — key rotation, security best practices, multiple keys
* **Data Guide** — full field reference for App Store review objects
* **Review Monitoring Guide** — scheduling, alerting, and database storage patterns
* **Integration Guides** — n8n, Google Sheets, and backend integration examples

***

## FAQ

<details>

<summary>How do I find an app's ID?</summary>

For App Store apps, the numeric ID is in the App Store URL:

```
https://apps.apple.com/us/app/instagram/id389801252
                                               ↑
                                     appId: 389801252
```

You can also pass a `bundleId` (e.g. `com.burbn.instagram`) instead of `appId` for App Store and Google Play endpoints.

</details>

<details>

<summary>How many requests do my free credits cover?</summary>

Credits are charged per query and per returned item. A query returning 50 reviews will cost 50 credits plus the cost of the query (1 credit per item). By checking the `pricing.creditsCharged` value in each response, you can see exactly how many credits each call has consumed.

</details>

<details>

<summary>What if I get a <code>401</code> error?</summary>

Your API key is missing or invalid. Confirm the `Authorization: Bearer YOUR_KEY` header is present and the key is active in your dashboard.

</details>

<details>

<summary>Can I use Pullbay from client-side JavaScript?</summary>

No — never expose your API key in browser or mobile code. Build a backend endpoint that adds the key server-side and proxies the response to your frontend.

</details>
