Skip to main content
Your organization API key (chd_org_...) is the master key. It can do everything — create instances, delete them, manage billing. You absolutely should not put it in a frontend, a mobile app, or hand it to a third-party integration. That’s where scoped keys come in. A scoped key (chd_sk_...) is locked down to specific instances and specific permissions. It can only do what you allow.

Why scoped keys?

  • Frontends: Your chat UI only needs to send messages and read status. Give it read + interact, nothing else.
  • Integrations: A Zapier workflow that installs skills? Give it configure on one instance.
  • End users: Give each user a key scoped to their instance with interact only. They can chat but can’t touch config.
  • Time-limited access: Set expires_at and the key auto-revokes.

Set up

export CHOWDER_KEY="chd_org_your_key_here"
export INSTANCE_ID="your-instance-id"
1
Create a scoped key
2
Let’s create a key for a frontend chat widget that can only read instance info and send messages to one specific instance:
3
curl -X POST https://api.chowder.dev/v1/keys \
  -H "Authorization: Bearer $CHOWDER_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"frontend-chat\",
    \"instance_ids\": [\"$INSTANCE_ID\"],
    \"permissions\": [\"read\", \"interact\"]
  }"
4
{
  "id": "b2f4e8a1-3c7d-4e9f-a5b6-1d8e3f7c2a94",
  "organization_id": "4737cccd-3d1d-4790-979b-6825d6a333de",
  "name": "frontend-chat",
  "key_prefix": "chd_sk_f3a8....",
  "is_active": true,
  "expires_at": null,
  "last_used_at": null,
  "created_at": "2026-02-14T12:00:00Z",
  "raw_key": "chd_sk_f3a8b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0"
}
5
The raw_key is only shown once — in this creation response. Copy it now. If you lose it, you’ll need to create a new key. Chowder only stores a hash of the key, not the key itself.
6
export SCOPED_KEY="chd_sk_f3a8b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0"
7
You can also set an expiration:
8
curl -X POST https://api.chowder.dev/v1/keys \
  -H "Authorization: Bearer $CHOWDER_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"temp-demo-key\",
    \"instance_ids\": [\"$INSTANCE_ID\"],
    \"permissions\": [\"read\", \"interact\"],
    \"expires_at\": \"2026-03-01T00:00:00Z\"
  }"
9
The key will automatically stop working after the expiration date.
10
Use the scoped key to send a message
11
The scoped key works just like your org key for the permissions you’ve granted:
12
curl -X POST https://api.chowder.dev/v1/instances/$INSTANCE_ID/responses \
  -H "Authorization: Bearer $SCOPED_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "input": "Hello from a scoped key!"
  }'
13
{
  "id": "resp_7a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "status": "completed",
  "model": "claude-sonnet-4-20250514",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "Hey there! Message received loud and clear."
        }
      ]
    }
  ]
}
14
Reading instance info also works (we granted read):
15
curl https://api.chowder.dev/v1/instances/$INSTANCE_ID \
  -H "Authorization: Bearer $SCOPED_KEY"
16
See it fail for admin operations
17
Now try something outside the key’s permissions — like stopping the instance:
18
curl -X POST https://api.chowder.dev/v1/instances/$INSTANCE_ID/stop \
  -H "Authorization: Bearer $SCOPED_KEY"
19
{
  "detail": "This endpoint requires an organization API key."
}
20
Or try accessing a different instance that the key isn’t scoped to:
21
curl https://api.chowder.dev/v1/instances/some-other-instance-id \
  -H "Authorization: Bearer $SCOPED_KEY"
22
{
  "detail": "No access to this instance."
}
23
The key is locked down exactly as configured. It can only do read and interact on the instance you specified.
24
List your keys
25
See all scoped keys in your organization:
26
curl https://api.chowder.dev/v1/keys \
  -H "Authorization: Bearer $CHOWDER_KEY"
27
[
  {
    "id": "b2f4e8a1-3c7d-4e9f-a5b6-1d8e3f7c2a94",
    "organization_id": "4737cccd-3d1d-4790-979b-6825d6a333de",
    "name": "frontend-chat",
    "key_prefix": "chd_sk_f3a8....",
    "is_active": true,
    "expires_at": null,
    "last_used_at": "2026-02-14T12:05:00Z",
    "created_at": "2026-02-14T12:00:00Z"
  }
]
28
Notice raw_key is not in the list response — only the key_prefix for identification. Chowder never returns the full key after creation.
29
Get detailed info on a specific key, including which instances and permissions it has:
30
curl https://api.chowder.dev/v1/keys/b2f4e8a1-3c7d-4e9f-a5b6-1d8e3f7c2a94 \
  -H "Authorization: Bearer $CHOWDER_KEY"
31
{
  "id": "b2f4e8a1-3c7d-4e9f-a5b6-1d8e3f7c2a94",
  "organization_id": "4737cccd-3d1d-4790-979b-6825d6a333de",
  "name": "frontend-chat",
  "key_prefix": "chd_sk_f3a8....",
  "is_active": true,
  "expires_at": null,
  "last_used_at": "2026-02-14T12:05:00Z",
  "created_at": "2026-02-14T12:00:00Z",
  "instances": [
    {
      "instance_id": "ead7b76b-f34e-4b91-93e7-9c979cf9e41c",
      "permissions": ["read", "interact"]
    }
  ]
}
32
Revoke a key
33
When a key is compromised or no longer needed:
34
curl -X DELETE https://api.chowder.dev/v1/keys/b2f4e8a1-3c7d-4e9f-a5b6-1d8e3f7c2a94 \
  -H "Authorization: Bearer $CHOWDER_KEY"
35
Returns 204 No Content. The key is immediately deactivated. Any request using it will get a 403 Forbidden.
36
Revoking a key is instant and permanent. Make sure you’re ready — any frontend or integration using that key will break immediately.

Permission reference

Here’s every permission you can assign to a scoped key:
PermissionWhat it grants
readView instance details and status (GET /v1/instances/{id}, GET /v1/instances/{id}/status)
interactSend messages and receive responses (POST /v1/instances/{id}/responses, session responses)
configureUpdate instance config, manage skills (PATCH /v1/instances/{id}, skills endpoints)
filesRead, write, delete, and move files in the instance workspace
channelsConnect, disconnect, and manage messaging channels
For a typical chat frontend, ["read", "interact"] is all you need. Start minimal and add permissions only when required.

Multi-instance keys

A single scoped key can access multiple instances with the same permissions:
curl -X POST https://api.chowder.dev/v1/keys \
  -H "Authorization: Bearer $CHOWDER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "dashboard-key",
    "instance_ids": [
      "ead7b76b-f34e-4b91-93e7-9c979cf9e41c",
      "c4a91d3e-8f2b-4e7a-b5c6-2d9f1e8a4b73",
      "f7e23b8d-1a4c-4d96-9e5f-3b7c2d8a1e64"
    ],
    "permissions": ["read", "interact", "configure"]
  }'
This is useful for admin dashboards that need to manage a fleet of instances.

Common patterns

{
  "name": "web-chat",
  "instance_ids": ["<instance-id>"],
  "permissions": ["read", "interact"]
}
Minimal access. Can read status and send messages. Can’t change config, manage channels, or delete anything.

What’s next?