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

# Authentication

Learn how to authenticate your requests to the Pullbay API using Bearer tokens. This guide covers getting your API key, implementing authentication in multiple languages, managing key security, and rotating keys safely.

## Getting Your API Key

Every Pullbay API request requires authentication with an API key.

{% stepper %}
{% step %}

## Sign in

Sign in to your [Pullbay Dashboard](https://dashboard.pullbay.com/)
{% endstep %}

{% step %}

## Open API Keys

Navigate to **API Keys** in the left sidebar
{% endstep %}

{% step %}

## Create a key

Click **Create New Key** and give it a name (e.g. "Production", "Development")
{% endstep %}

{% step %}

## Copy the key

Copy the key
{% endstep %}
{% endstepper %}

**Never share your API keys.** Treat them like passwords.

## How to Authenticate

Every request to the Pullbay API must include your API key in the `Authorization` header using the Bearer scheme:

```
Authorization: Bearer YOUR_API_KEY
```

### cURL

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

### Python

```python
import requests
import os

api_key = os.environ["PULLBAY_API_KEY"]

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

### Node.js (Axios)

```javascript
const axios = require('axios');

const apiKey = process.env.PULLBAY_API_KEY;

const response = await axios.get(
  'https://api.pullbay.com/appstore/reviews',
  {
    params: { appId: '284882215', maxItems: 5 },
    headers: { 'Authorization': `Bearer ${apiKey}` },
  }
);

console.log(response.data);
```

### Node.js (Fetch)

```javascript
const apiKey = process.env.PULLBAY_API_KEY;

const params = new URLSearchParams({ appId: '284882215', maxItems: '5' });
const response = await fetch(
  `https://api.pullbay.com/appstore/reviews?${params}`,
  {
    method: 'GET',
    headers: { 'Authorization': `Bearer ${apiKey}` },
  }
);

const data = await response.json();
console.log(data);
```

### PHP

```php
<?php
$apiKey = getenv('PULLBAY_API_KEY');
$url    = 'https://api.pullbay.com/appstore/reviews?appId=284882215&maxItems=5';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $apiKey,
]);

$response = curl_exec($ch);
$data     = json_decode($response, true);
print_r($data);
```

### Go

```go
package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    apiKey := os.Getenv("PULLBAY_API_KEY")
    url    := "https://api.pullbay.com/appstore/reviews?appId=284882215&maxItems=5"

    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", apiKey))

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
```

## Authentication Errors

A failed authentication returns `401 Unauthorized`:

```json
{
  "requestId": "3b8dcb68-1f8c-4a7b-b9e7-63a7b9986f24",
  "status": 401,
  "message": "Unauthorized",
  "success": false,
  "error": { "code": "AUTHENTICATION_UNAUTHORIZED" }
}
```

| Cause                          | Solution                                                                   |
| ------------------------------ | -------------------------------------------------------------------------- |
| Missing `Authorization` header | Add `Authorization: Bearer YOUR_API_KEY` to every request                  |
| Wrong header format            | Must be `Authorization: Bearer YOUR_KEY` — capital B, space after "Bearer" |
| API key revoked                | Generate a new key in the dashboard and update your application            |
| API key not yet active         | Wait a few seconds after creation and retry                                |

Failed requests — including `401` — **do not consume credits**.

## API Key Management

### Creating a Key

{% stepper %}
{% step %}

## Go to API Keys

Go to [dashboard.pullbay.com](https://dashboard.pullbay.com/) → **API Keys**
{% endstep %}

{% step %}

## Create a key

Click **Create New Key**
{% endstep %}

{% step %}

## Name the key

Add a descriptive name (e.g. "Mobile App", "Analytics Dashboard", "n8n Workflow")
{% endstep %}

{% step %}

## Copy it

Click **Create** and copy the key immediately
{% endstep %}
{% endstepper %}

### Rotating a Key Safely (Zero Downtime)

{% stepper %}
{% step %}

## Create a new key

Create a new key alongside the old one — both work at the same time
{% endstep %}

{% step %}

## Update applications

Update all applications to use the new key; test in staging first
{% endstep %}

{% step %}

## Deploy and verify

Deploy the changes to all instances and verify requests are succeeding with the new key
{% endstep %}

{% step %}

## Revoke the old key

Revoke the old key once you're confident nothing still uses it — this invalidates it immediately
{% endstep %}
{% endstepper %}

### Revoking a Key

{% stepper %}
{% step %}

## Open API Keys

Go to **API Keys** in the dashboard
{% endstep %}

{% step %}

## Find the key

Find the key you want to revoke
{% endstep %}

{% step %}

## Revoke it

Click the three-dot menu → **Revoke**
{% endstep %}

{% step %}

## Confirm

Confirm — the key is invalidated immediately
{% endstep %}
{% endstepper %}

Any application still using the revoked key will begin receiving `401` responses. Update your code before revoking.

### Viewing Key Usage

Go to **API Keys**, select a key, and view its activity log:

* Total requests made with this key
* Requests by endpoint
* Requests by date
* Credits consumed

## Security Best Practices

### Storage

* **Use environment variables** — never hardcode a key in source code
* **Use a secrets manager** in production (AWS Secrets Manager, Google Secret Manager, HashiCorp Vault)
* **Add `.env` files to `.gitignore`** — keys committed to version control are exposed even if later removed

```python
import os
api_key = os.environ["PULLBAY_API_KEY"]  # Correct — read from environment
api_key = "abc123..."                    # Never do this
```

### Access

* **One key per application** — use separate keys for your mobile app, backend service, n8n workflow, and so on
* **Keep live keys out of development** — use a key scoped to your development environment for local testing
* **Rotate every 90 days** or whenever team membership changes
* **Revoke unused keys** promptly — unused keys are attack surface

### What Not to Do

* **Don't commit keys to Git** — even if you remove them later, they remain in commit history
* **Don't include keys in client-side code** — browser JavaScript is readable to anyone
* **Don't share keys via email, Slack, or chat** — use a password manager or secrets manager
* **Don't log keys** — make sure debug output and log files never capture the `Authorization` header

## Common Questions

<details>

<summary>Can I have multiple API keys?</summary>

Yes — create as many keys as you need. Common patterns:

* One key per application (mobile app, backend service, automation workflow)
* One key per environment (development, staging, production)
* One key per team member for individual usage tracking

Each key is independently revocable without affecting the others.

</details>

<details>

<summary>How do I rotate a key without downtime?</summary>

Create a new key first, update all applications to use it, verify everything works, then revoke the old key. Both keys are valid simultaneously during the transition so there is no gap in service.

</details>

<details>

<summary>What should I do if my API key is compromised?</summary>

Act immediately:

1. Revoke the compromised key from the dashboard
2. Create a new key
3. Update all applications and redeploy
4. Review recent usage in the dashboard for any suspicious requests made while the key was exposed

</details>

<details>

<summary>Can I restrict what endpoints a key can access?</summary>

Yes, you can restrict your API keys on a per-endpoint basis.

</details>
