> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parse.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticated APIs

> Call APIs that require login credentials

Some Parse APIs are built from sites that require login. These APIs have **login endpoints** that create sessions and **protected endpoints** that reuse the authenticated state.

<Note>
  Authenticated APIs can only be created through the [Parse dashboard](https://parse.bot) — not via the API or MCP. Free accounts cannot create authenticated APIs, and each account is limited to 1 authenticated session per site.
</Note>

## Endpoint session tags

Each endpoint in an authenticated API has a session tag:

| Tag                           | Meaning                                                                                        |
| ----------------------------- | ---------------------------------------------------------------------------------------------- |
| `initiates_session: true`     | Login endpoint. Returns `session_id` + `encryption_key` in the response.                       |
| `depends_on_session: "login"` | Protected endpoint. Requires `session_id` + `encryption_key` from a prior login call.          |
| *(neither)*                   | Public endpoint. Works without any session, even on APIs that have other auth-gated endpoints. |

## Step 1: Call the login endpoint

```bash theme={null}
curl -X POST https://api.parse.bot/scraper/{scraper_id}/login \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "user@example.com", "password": "s3cret"}'
```

The response includes your data plus two session values:

```json theme={null}
{
  "data": { "logged_in": true, "display_name": "Jane" },
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "encryption_key": "gAAAAABk..."
}
```

<Warning>
  Store both `session_id` and `encryption_key` — you need them for every protected endpoint call. Parse does not store the encryption key.
</Warning>

## Step 2: Call protected endpoints

Pass the session credentials via headers (preferred) or request body:

```bash theme={null}
# Option A: Headers (recommended)
curl -X POST https://api.parse.bot/scraper/{scraper_id}/get_inbox \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-Session-ID: 550e8400-e29b-41d4-a716-446655440000" \
  -H "X-Encryption-Key: gAAAAABk..." \
  -H "Content-Type: application/json" \
  -d '{"folder": "inbox", "limit": 10}'

# Option B: Body params
curl -X POST https://api.parse.bot/scraper/{scraper_id}/get_inbox \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "550e8400-e29b-...",
    "encryption_key": "gAAAAABk...",
    "folder": "inbox",
    "limit": 10
  }'
```

The session state is automatically updated after each call — you don't need to track cookies or tokens yourself.

## Full example

```python theme={null}
import httpx

API_KEY = "your-api-key"
BASE = "https://api.parse.bot"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

scraper_id = "scraper-456"

with httpx.Client(headers=HEADERS, timeout=60) as client:
    # 1. Login
    resp = client.post(f"{BASE}/scraper/{scraper_id}/login", json={
        "username": "user@example.com",
        "password": "s3cret",
    })
    login = resp.json()
    session_id = login["session_id"]
    encryption_key = login["encryption_key"]

    # 2. Call a protected endpoint
    resp = client.post(
        f"{BASE}/scraper/{scraper_id}/get_inbox",
        headers={
            **HEADERS,
            "X-Session-ID": session_id,
            "X-Encryption-Key": encryption_key,
        },
        json={"folder": "inbox", "limit": 10},
    )
    print(resp.json())
```

## Session details

* **One session per user per scraper**: Logging in again with the same user upserts the existing session.
* **Proxy binding**: The proxy IP used during login is reused for all protected endpoints to prevent session invalidation from IP changes.
* **Session updates are transparent**: After each protected call, the session state is re-encrypted and saved automatically.
* **Rate limiting**: Login endpoints enforce a rate limit of 3 login attempts per hour per scraper.

## Error responses

| Code | Detail                                                                                 | When                                                          |
| ---- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| 400  | `This endpoint requires session_id and encryption_key. Call the login endpoint first.` | Protected endpoint called without session                     |
| 400  | `Invalid session or encryption key`                                                    | Wrong encryption key or corrupted session                     |
| 404  | `Session not found`                                                                    | Invalid session\_id or session belongs to a different scraper |
| 403  | Auth session limit reached                                                             | You've hit your per-site session cap                          |

## Security

* **Fernet session encryption**: Session state is encrypted with your `encryption_key` before storage. Parse stores only ciphertext — without your key, the data is unreadable.
* **HMAC replay protection**: Serialized session blobs are signed with a 30-minute TTL.
* **No plaintext credential storage**: Credentials provided during API creation are encrypted end-to-end and never stored in plaintext.
