Authentication and API keys
Project API keys, scopes, the per-resource permission matrix, projects and roles, and calling the API from a browser page.
Keys
A key belongs to one project. Owners and admins create keys in the console (Configuration → API keys) or through the API with an account session; the secret is returned once.
Authorization: Bearer sk_…| Property | Meaning |
|---|---|
scopes | read is always present; execute allows runs, browsers, actions and writes |
expires_in_days | 1–365, default 90; can be extended from now with PATCH |
permissions | Optional per-group ceiling, below (a group left out takes the scope level) |
last_used_at, revoked_at | Metadata the list shows; secrets are stored hashed and never returned again |
A key already selects its project; an X-Project-Id header, if sent, must match. Invalid bearer credentials never fall back to a cookie session.
Managing keys
| Method and path | Result |
|---|---|
GET /v1/api-keys | Metadata only |
POST /v1/api-keys | { "name", "scopes": ["read","execute"], "expires_in_days"?, "permissions"? } → metadata plus the one-time secret |
PATCH /v1/api-keys/{id} | name, expires_in_days (from now), permissions (the groups named change, the rest keep their level); scopes are not editable — create a new key |
POST /v1/api-keys/{id}/rotate | A new one-time secret; the old one stops at once; name, scopes, permissions and expiry stay |
POST /v1/api-keys/{id}/revoke | Idempotent; already accepted work is not cancelled — use the resource's cancel or stop |
These routes need an account session with the owner or admin role. A key cannot manage keys, accounts or projects.
Permission matrix
permissions narrows a key per resource group to none, read or write, never above its scopes:
| Group | Covers |
|---|---|
agents | runs, sessions, models |
browsers | browsers, their assets, proxy policy and credential reads |
workspaces | Workspaces and files |
profiles | Profiles |
schedules | Schedules (read; management needs a session) |
integrations | Integrations (read; management needs a session) |
billing | Billing account, ledger, statement, rates |
The router reads the group off the path. History, usage and /v1/projects/current are open to any key that may read at least one group. A key created before the matrix existed is every group at its scope level.
Projects and roles
Sign-up creates one Default Project with the account as owner. Roles, checked server-side on every request:
| Role | Can |
|---|---|
| owner / admin | Manage the project: keys, members, credentials, models, schedules, webhooks, integrations, deletions |
| member | Execute: runs, browsers, actions, files, profiles |
| viewer | Read |
A resource in a project you cannot see answers not_found (404); an action your role does not permit answers permission_denied (403). Account sessions choose a project with X-Project-Id; without it, the default project is selected.
From a browser page
The API is server-side only by default: no CORS headers, so a page on another origin cannot call it. A deployment may allowlist page origins (STEALTH_CORS_ORIGINS); those origins get the preflight and Access-Control-Allow-Origin, for project keys only — no credentials header, and a cross-origin request without a bearer key answers 401 before any cookie could count.
Request conventions
- JSON bodies,
Content-Type: application/json, normally at most 16 KiB, received within five seconds. Unknown fields are rejected withinvalid_request. - Creates accept
Idempotency-Key(1–128 visible ASCII characters): the same key with the same body returns the same resource; a different body answersconflict. - Every response carries
X-Request-Id; errors repeat it in the envelope — see Errors. - Lists are
{ "data": [...] }; long-running creates answer202with aLocationheader.
