> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sempera.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication and credentials

> API keys, kinds, scopes, roles, the browser session token, service and CI identities, and what each can never do.

One hostname does not mean one credential. Each class exists for one job and can never do another's.

| Class | Used by | How it authenticates | What it can never do |
| - | - | - | - |
| Customer App session | `app.sempera.org` | Host-only, HttpOnly, Secure cookie plus a CSRF token on writes | Be presented to `api.sempera.org` |
| Developer key (`kind: developer`) | A developer's server | `Authorization: Bearer sempera_sk_...` | Mint keys (`api_keys:write`) |
| Runtime key (`kind: runtime`) | The agent runtime executing tools | Bearer | Publish, edit or create agents, manage keys, read other workspaces, touch billing |
| Web session token | A browser in a Web voice conversation | The short-lived token `POST /v1/sessions` returns, bound to one room | Anything but join that one conversation |
| Service key (`kind: service`) | An internal Sempera service | Bearer | Publish, manage keys |
| CI key (`kind: ci`) | Deployment and smoke automation | Bearer, read-only scopes | Write anything |
| Admin key (`kind: admin`) | A workspace owner's elevated automation | Bearer | Leave its workspace |
| OAuth client | ChatGPT, Claude, Codex or Grok Bot, approved by a workspace owner | `Authorization: Bearer sempera_at_...`, one hour, refreshed by a rotating token | Reach anything but `POST /v1/mcp`, or hold a scope beyond `phone:read`, `phone:call` and `phone:text` |
| REST client credential | A client that cannot do OAuth, such as Muse | `Authorization: Bearer sempera_sk_...` | Reach anything but the phone routes, or buy anything |
| Third-party webhook | The payment provider, the telephony carrier | The provider's own signature or shared token | Reach any other route |

## API keys

The `Authorization` 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`, `operator` or `viewer`, 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_scope` before anything runs. `kind` caps which scopes a key may hold at all.

Scopes: `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 with `POST /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 the `401` 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](https://docs.sempera.org/mcp.md#sign-in-with-oauth).

**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 calls `POST /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 on `app.sempera.org` and never on the API.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.