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
configureon one instance. - End users: Give each user a key scoped to their instance with
interactonly. They can chat but can’t touch config. - Time-limited access: Set
expires_atand the key auto-revokes.
Set up
Let’s create a key for a frontend chat widget that can only read instance info and send messages to one specific instance:
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\"]
}"
{
"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"
}
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.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\"
}"
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!"
}'
{
"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."
}
]
}
]
}
curl -X POST https://api.chowder.dev/v1/instances/$INSTANCE_ID/stop \
-H "Authorization: Bearer $SCOPED_KEY"
curl https://api.chowder.dev/v1/instances/some-other-instance-id \
-H "Authorization: Bearer $SCOPED_KEY"
The key is locked down exactly as configured. It can only do
read and interact on the instance you specified.[
{
"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"
}
]
Notice
raw_key is not in the list response — only the key_prefix for identification. Chowder never returns the full key after creation.curl https://api.chowder.dev/v1/keys/b2f4e8a1-3c7d-4e9f-a5b6-1d8e3f7c2a94 \
-H "Authorization: Bearer $CHOWDER_KEY"
{
"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"]
}
]
}
curl -X DELETE https://api.chowder.dev/v1/keys/b2f4e8a1-3c7d-4e9f-a5b6-1d8e3f7c2a94 \
-H "Authorization: Bearer $CHOWDER_KEY"
Returns
204 No Content. The key is immediately deactivated. Any request using it will get a 403 Forbidden.Permission reference
Here’s every permission you can assign to a scoped key:| Permission | What it grants |
|---|---|
read | View instance details and status (GET /v1/instances/{id}, GET /v1/instances/{id}/status) |
interact | Send messages and receive responses (POST /v1/instances/{id}/responses, session responses) |
configure | Update instance config, manage skills (PATCH /v1/instances/{id}, skills endpoints) |
files | Read, write, delete, and move files in the instance workspace |
channels | Connect, disconnect, and manage messaging channels |
Multi-instance keys
A single scoped key can access multiple instances with the same permissions:Common patterns
- Chat frontend
- Admin dashboard
- Temp demo access