Skip to main content

Authentication

Every request to the Chowder API requires an API key passed as a Bearer token:
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:
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": { ... }
# }
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.
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.
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:
PermissionWhat it allows
readView instance details and status
interactSend messages (call /responses)
configureUpdate instance config, start/stop
filesRead, write, and manage workspace files
channelsConnect, disconnect, and manage channels
For a frontend that just needs to send and receive messages:
{
  "name": "chat-widget",
  "instance_ids": ["inst_abc123"],
  "permissions": ["read", "interact"]
}

Expiration

Scoped keys can optionally expire:
{
  "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:
1

Key generation

A cryptographically random key is generated with the appropriate prefix (chd_org_ or chd_sk_).
2

Hash storage

The key is hashed with SHA-256. Only the hash is stored in the database.
3

Key returned once

The raw key is returned in the creation response. This is the only time you’ll see it.
4

Authentication

On each request, Chowder hashes the key from the Authorization header and looks up the hash in the database.
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.

Managing keys

# 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..."
Revoking a key is immediate and permanent. Any request using that key will start returning 403 right away.

Which key should I use?

Use an org key when...

You’re building backend services, admin tools, or anything that runs on infrastructure you control. The key never leaves your server.

Use a scoped key when...

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.
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.