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

# Authentication

> How API keys work in Chowder — organization keys vs. scoped keys, permissions, and when to use which.

# Authentication

Every request to the Chowder API requires an API key passed as a Bearer token:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
curl https://api.chowder.dev/v1/instances \
  -H "Authorization: Bearer chd_org_abc123..."
```

There are two types of keys, and they serve very different purposes.

## Organization keys

**Prefix:** `chd_org_*`

Organization keys are the master keys. They have full, unrestricted access to everything in your organization: instances, channels, skills, files, billing, other keys — everything.

You get one automatically when you sign up:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
curl -X POST https://api.chowder.dev/v1/organization/signup \
  -H "Content-Type: application/json" \
  -d '{"name": "my-org"}'

# Response:
# {
#   "api_key": "chd_org_a1b2c3d4e5f6...",
#   "organization": { ... }
# }
```

<Warning>
  The raw API key is only shown **once** — at creation. Chowder stores a SHA-256 hash of the key, not the key itself. If you lose it, you'll need to create a new one.
</Warning>

**Use org keys for:**

* Backend services that manage instances
* Admin dashboards
* CI/CD pipelines
* Anything that needs full control

**Never use org keys for:**

* Client-side code
* User-facing frontends
* Anything where the key could be exposed

## Scoped keys

**Prefix:** `chd_sk_*`

Scoped keys are restricted keys. They only work with specific instances and only have specific permissions. This is what you hand out when you don't want to give away the kingdom.

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
curl -X POST https://api.chowder.dev/v1/keys \
  -H "Authorization: Bearer chd_org_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "frontend-key",
    "instance_ids": ["inst_abc123"],
    "permissions": ["read", "interact"]
  }'

# Response:
# {
#   "id": "key_xyz...",
#   "raw_key": "chd_sk_f7g8h9...",
#   "name": "frontend-key",
#   ...
# }
```

### Permissions

Each scoped key gets a set of permissions that control what it can do:

| Permission  | What it allows                           |
| ----------- | ---------------------------------------- |
| `read`      | View instance details and status         |
| `interact`  | Send messages (call `/responses`)        |
| `configure` | Update instance config, start/stop       |
| `files`     | Read, write, and manage workspace files  |
| `channels`  | Connect, disconnect, and manage channels |

<Tabs>
  <Tab title="Chat-only key">
    For a frontend that just needs to send and receive messages:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    {
      "name": "chat-widget",
      "instance_ids": ["inst_abc123"],
      "permissions": ["read", "interact"]
    }
    ```
  </Tab>

  <Tab title="Admin key">
    For a dashboard that manages channels and config:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    {
      "name": "admin-panel",
      "instance_ids": ["inst_abc123", "inst_def456"],
      "permissions": ["read", "interact", "configure", "channels"]
    }
    ```
  </Tab>

  <Tab title="File manager key">
    For a service that uploads documents to the workspace:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    {
      "name": "document-uploader",
      "instance_ids": ["inst_abc123"],
      "permissions": ["files"]
    }
    ```
  </Tab>
</Tabs>

### Expiration

Scoped keys can optionally expire:

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "name": "temp-access",
  "instance_ids": ["inst_abc123"],
  "permissions": ["read", "interact"],
  "expires_at": "2026-03-01T00:00:00Z"
}
```

After the expiration date, the key returns a `403`.

## How keys are stored

Chowder never stores raw API keys. Here's what happens:

<Steps>
  <Step title="Key generation">
    A cryptographically random key is generated with the appropriate prefix (`chd_org_` or `chd_sk_`).
  </Step>

  <Step title="Hash storage">
    The key is hashed with SHA-256. Only the hash is stored in the database.
  </Step>

  <Step title="Key returned once">
    The raw key is returned in the creation response. This is the only time you'll see it.
  </Step>

  <Step title="Authentication">
    On each request, Chowder hashes the key from the `Authorization` header and looks up the hash in the database.
  </Step>
</Steps>

<Note>
  This means Chowder **cannot** recover your key. If you lose it, revoke it and create a new one. This is by design — it protects you even if the database is compromised.
</Note>

## Managing keys

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
# List all scoped keys
curl https://api.chowder.dev/v1/keys \
  -H "Authorization: Bearer chd_org_abc123..."

# Get details about a specific key (shows instance access)
curl https://api.chowder.dev/v1/keys/{key_id} \
  -H "Authorization: Bearer chd_org_abc123..."

# Revoke a key (immediate, permanent)
curl -X DELETE https://api.chowder.dev/v1/keys/{key_id} \
  -H "Authorization: Bearer chd_org_abc123..."
```

<Warning>
  Revoking a key is immediate and permanent. Any request using that key will start returning `403` right away.
</Warning>

## Which key should I use?

<CardGroup cols={2}>
  <Card title="Use an org key when..." icon="shield">
    You're building backend services, admin tools, or anything that runs on infrastructure you control. The key never leaves your server.
  </Card>

  <Card title="Use a scoped key when..." icon="key">
    You're building user-facing apps, chat widgets, or anything where the key might be visible in network requests. Lock it down to specific instances and minimum permissions.
  </Card>
</CardGroup>

A good pattern: your backend uses an org key to manage instances and create scoped keys, then hands scoped keys to your frontend so users can chat with specific agents without accessing anything else.
