API keys
TheAuthorization header value is Bearer <api-key>. Replace <api-key> with your key; the angle brackets are placeholder notation, not part of it. Send the key as Authorization: Bearer sempera_sk_.... No other header or scheme is recognised; a key on any route outside /v1 is ignored.
A key has:
- a workspace: the one customer account it lives in;
- a role:
owner,operatororviewer, the same ladder a person has in the workspace. A key is never minted above the role of whoever minted it, and each kind has a ceiling (a runtime or CI key is at most a viewer); - scopes: an explicit list. Each route names the scope it needs; a key without it gets
403 insufficient_scopebefore anything runs.kindcaps which scopes a key may hold at all.
agents:read, agents:write, agents:publish, sessions:read, sessions:write, calls:read, calls:write, phone_numbers:read, phone_numbers:write, tools:read, tools:write, tools:execute, integrations:read, integrations:write, knowledge:read, knowledge:write, tests:read, tests:write, evals:read, evals:write, workspaces:read, workspaces:write, organizations:read, api_keys:read, api_keys:write, webhooks:read, webhooks:write, deploy:read, models:read, prompts:read, prompts:write, phone:read, phone:call, phone:text.
Authorization is two locks: the scope (what the credential was minted for) and the role (what that identity may do to the resource). Both must pass. Default is deny.
Minting and revoking
A workspace owner creates keys in the Sempera App under Settings, API keys, or withPOST /v1/api-keys (owner only, api_keys:write); either way the secret is shown once. The first key of a workspace is created in the App, because creating a key needs an owner’s signed-in session or an admin key, and a developer key can never mint keys. GET /v1/api-keys lists keys without secrets. DELETE /v1/api-keys/{id} revokes immediately. GET /v1/me describes the calling credential.
Connected clients
Each outside client gets its own grant, so one can be ended without touching another. An owner sees them all in Settings, Connected clients, with scopes and last use. OAuth, for MCP hosts. The host discovers the door from the401 on POST /v1/mcp, registers itself, and sends the browser to a consent page on app.sempera.org. Only a signed-in workspace owner can approve, and no key or token can do it for them. The grant covers one client in one workspace with the scopes approved there, and approving the same client again replaces it. The flow is authorization code with PKCE (S256), exact redirects and audience binding to https://api.sempera.org/v1/mcp. Details are in MCP.
A scoped REST credential, for a client that cannot do OAuth. An owner creates one in Settings, Connected clients, or with POST /v1/client-grants/rest (client, scopes, optional expires_in_days). It holds phone scopes only, works on the phone routes only, expires in 90 days by default (at most 365), and is shown once.
GET /v1/client-grants lists every connected client (OAuth, MCP keys and REST credentials) and DELETE /v1/client-grants/{grant_id} ends one. An ordinary API key, another workspace’s client and an unknown id all read as not_found.
Browser clients
A browser never holds an API key. Your server callsPOST /v1/sessions and hands the browser the returned token and url; the token is scoped to one room and expires with the conversation.
Sign-in for people
People sign in to the Sempera App with Google, Apple, email or phone. Those roads live onapp.sempera.org and never on the API.