Authentication
API keys as Bearer tokens, the read and write scopes, and what 401 and 403 responses mean.
API keys
Every request carries a first-party API key as a Bearer token:
Authorization: Bearer sbk_live_…Keys are created in the app under Settings → API Keys. A key belongs to
the workspace it was created in and acts as the user who created it; it sees
that workspace's projects and nothing else. Another workspace's ids answer
404, never 403 — existence is not disclosed.
The full key is shown once, at creation. The app keeps only the display
prefix (sbk_live_a1b2…) and the time the key was last used, so a lost key is
replaced, not recovered. Revoking a key takes effect on its next request.
Scopes
A key's scope is chosen when it is created and cannot be widened later:
| Level in the app | Scopes | Allows |
|---|---|---|
| Read-only | read | GET /v1/me, credits, models, and every read of projects, files, scenes, artifacts, operations, sessions and the library |
| Read & write | read, write | Everything above, plus creating and changing entities, uploading files and artifacts, running steps, posting messages, cancel |
write does not imply read. The app always mints Read & write as both,
which is what API clients and the MCP server need. Each
operation in the reference names the scope it requires.
Responses
401 Unauthorized — no key, an unknown key, or a revoked one. The
response carries WWW-Authenticate: Bearer and a problem document:
{
"type": "about:blank",
"title": "Unauthorized",
"status": 401,
"detail": "Missing API key",
"instance": "/v1/me"
}403 Forbidden — the key is live but lacks the scope the operation
needs. Because the caller is authenticated, the response names the missing
scope, as RFC 6750 §3.1 specifies:
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", scope="write"
Content-Type: application/problem+json{
"type": "https://scenebrew.com/problems/insufficient-scope",
"title": "Forbidden",
"status": 403,
"detail": "This operation requires the 'write' scope",
"instance": "/v1/scenes/0192a7c4-3f5e-7c8a-9b1d-2e3f4a5b6c7d/steps",
"code": "insufficient_scope"
}The fix is a new key at the Read & write level; scopes are fixed for the life of a key.
Keeping keys safe
- Put keys in environment variables or your CI's secret store, never in
source. The prefix is
sbk_live_followed by 40 characters — add that pattern to your secret scanner. - Use one key per environment or integration, named after it, so the last used column in the app tells you what is alive.
- Rotate by creating the replacement first, switching, then revoking the old key.
- Presigned download URLs — on artifacts and files — are separate,
short-lived credentials: they need no header and expire at
download_expires_at(equivalently, afterdownload_expires_inseconds). Do not store them.
Playground
Each reference page has a playground that sends requests from your browser directly to the API. Your key is kept in the browser for the session and never passes through this site.