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

# Authentication

> API key and session authentication, route coverage, and common auth failures.

Shelv supports two auth methods:

* API keys for programmatic access (`Authorization: Bearer sk_...`)
* Session cookies for dashboard access

## Route auth matrix

| Route family      | API key | Session | Public |
| ----------------- | ------- | ------- | ------ |
| `/v1/auth/*`      | No      | No      | Yes    |
| `/v1/shelves*`    | Yes     | Yes     | No     |
| `/v1/webhooks*`   | Yes     | Yes     | No     |
| `/v1/dashboard/*` | No      | Yes     | No     |

Session auth is intended for dashboard flows. API integrations should use API keys so requests stay decoupled from browser state.
For automation and sandbox integrations, use API keys instead of session cookies so jobs are reproducible and decoupled from browser state.

## Get an API key

<Tabs>
  <Tab title="API">
    No browser required — ideal for AI agents and developers using coding agents (Claude Code, Codex, OpenClaw).

    **Step 1: Register an account**

    ```bash theme={"theme":{"light":"github-light","dark":"poimandres"}}
    curl -X POST https://api.shelv.dev/v1/auth/register \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Alice",
        "email": "alice@example.com",
        "password": "your-secure-password"
      }'
    ```

    ```json 201 Created theme={"theme":{"light":"github-light","dark":"poimandres"}}
    {
      "message": "Verification code sent to your email address. Check your inbox."
    }
    ```

    **Step 2: Check your email for the 6-digit verification code**

    **Step 3: Verify your email and receive an API key**

    ```bash theme={"theme":{"light":"github-light","dark":"poimandres"}}
    curl -X POST https://api.shelv.dev/v1/auth/verify-email \
      -H "Content-Type: application/json" \
      -d '{
        "email": "alice@example.com",
        "code": "123456"
      }'
    ```

    ```json 200 OK theme={"theme":{"light":"github-light","dark":"poimandres"}}
    {
      "user": {
        "id": "usr_abc123",
        "name": "Alice",
        "email": "alice@example.com"
      },
      "apiKey": {
        "key": "sk_live_...",
        "prefix": "sk_live_...",
        "expiresAt": null
      }
    }
    ```

    Save `apiKey.key` — this is your `SHELV_API_KEY`. It is shown once.
  </Tab>

  <Tab title="Dashboard">
    1. Sign in at [shelv.dev](https://shelv.dev)
    2. Open **Settings > API Keys**
    3. Create a key and store it securely (the raw token is shown once)
  </Tab>
</Tabs>

## Use API keys

Send the `Authorization` header on every request to `/v1/shelves*` and `/v1/webhooks*`:

<CodeGroup>
  ```bash curl theme={"theme":{"light":"github-light","dark":"poimandres"}}
  curl https://api.shelv.dev/v1/shelves \
    -H "Authorization: Bearer sk_your_api_key"
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"poimandres"}}
  const res = await fetch("https://api.shelv.dev/v1/shelves", {
    headers: { Authorization: `Bearer ${process.env.SHELV_API_KEY}` },
  });
  const shelves = await res.json();
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"poimandres"}}
  import os
  import requests

  res = requests.get(
      "https://api.shelv.dev/v1/shelves",
      headers={"Authorization": f"Bearer {os.environ['SHELV_API_KEY']}"},
  )
  shelves = res.json()
  ```
</CodeGroup>

## Error model

Authentication failure (`401`):

```json theme={"theme":{"light":"github-light","dark":"poimandres"}}
{
  "code": "UNAUTHORIZED",
  "message": "Invalid or missing authentication"
}
```

Rate limit hit (`429`):

```json theme={"theme":{"light":"github-light","dark":"poimandres"}}
{
  "code": "RATE_LIMITED",
  "message": "Too many requests, please try again later."
}
```

Status-gated access (`409`) can happen when a shelf is not yet eligible for a requested operation (for example requesting `tree` or `archive-url` before processing completes).

## Rate limits

| Scope                               | Limit                         |
| ----------------------------------- | ----------------------------- |
| Auth routes (`/v1/auth/*`)          | 10 requests / 15 minutes (IP) |
| Auth routes (`/api/auth/**`)        | 10 requests / 15 minutes (IP) |
| Authenticated reads                 | 120 requests / minute (user)  |
| Authenticated writes                | 20 requests / minute (user)   |
| Shelf creation (`POST /v1/shelves`) | 10 requests / hour (user)     |

## Operational best practices

* Keep keys in environment variables, never source code
* Use separate keys for dev/staging/prod
* Rotate and revoke keys regularly

For incident response, revoke compromised keys immediately and issue replacement keys per environment.
