# Authentication

Two kinds of credential reach the API and the MCP server: an API key you create for your own code, and a short-lived token an assistant obtains when a workspace owner connects it. Both are scoped to one workspace, and both work on either transport.

## API keys

Create a key under Settings → API keys. Give it a name and pick a tier; the tier fixes what the key may do for its whole life. The full secret is shown once, at creation. Revoke a key from the same pane; revocation is immediate. A workspace can hold 10 active keys; one key per tool is the habit that keeps a revoke from breaking anything else.

Keys start with `sa_live_` (older keys starting with `sk_live_` still work). Send one as a bearer token on every request. The old `?api_key=` query parameter is no longer accepted and returns an error that says so.

```bash
curl https://app.streamagent.io/api/mcp \
  -H "Authorization: Bearer sa_live_…" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```
_List the tools your key can call._

```bash
curl https://app.streamagent.io/api/v1/workspace \
  -H "Authorization: Bearer sa_live_…"
```
_The same key on the REST API._

## Using a credential on the REST API

Every route under `https://app.streamagent.io/api/v1` takes the same bearer header and checks the same scope as the MCP tool of the same name; a key that can list leads over MCP can `GET /leads`, and a key that cannot, cannot. Errors come back as `{ "error": { "code", "message" } }` with the HTTP status the code implies, lists page with `limit` and `cursor`, and writes accept an `Idempotency-Key`. The full conventions and the route table are on the [REST API](/docs/api) page.

## Key tiers and what they expand to

A tier is a fixed set of scopes. The authorizer checks the scope a tool requires against this set on every call.

| Tier | Value | Scopes |
| --- | --- | --- |
| Read | `read` | `videos:read`, `leads:read`, `analytics:read`, `transcripts:read`, `routes:read`, `workspace:read`, `outcomes:read` |
| Read & write | `readwrite` | `videos:read`, `videos:write`, `leads:read`, `leads:write`, `analytics:read`, `transcripts:read`, `routes:read`, `routes:write`, `workspace:read`, `outcomes:read` |
| Admin | `admin` | `videos:read`, `videos:write`, `leads:read`, `leads:write`, `analytics:read`, `transcripts:read`, `routes:read`, `routes:write`, `workspace:read`, `outcomes:read`, `channel:write`, `workspace:manage` |

> Read-only keys cannot change anything. Read & write keys can update videos, leads and routes but never delete; archiving is reversible. Only Admin keys can curate the public channel page.

## Scopes

Assistants connected through sign-in request scopes individually and the workspace owner approves the exact set on a consent screen. Keys get their scopes from the tier above.

| Scope | Grants | Covers |
| --- | --- | --- |
| `videos:read` | View your videos | Library, key moments & comparisons |
| `videos:write` | Add and update your videos | Add videos, titles, descriptions, tags & archive |
| `leads:read` | View your leads | Profiles, scores & full journeys |
| `leads:write` | Add and update your leads | Add leads, status, tags, notes & details |
| `analytics:read` | View your analytics | Views, retention curves & trends |
| `transcripts:read` | Search your video transcripts | Full transcripts & moment search |
| `routes:read` | View your routes | Flows, steps & branches |
| `routes:write` | Create and edit your routes | Build flows, steps & branches |
| `workspace:read` | View your workspace settings | Plan, usage, tags & brand voice |
| `channel:write` | Curate your channel page | Featured pick, visibility & identity |
| `outcomes:read` | View your revenue outcomes | Purchases, booked calls & refunds with value |
| `workspace:manage` | Manage webhooks and API keys | Endpoints, secrets, delivery log & keys |

## Assistant connections

Claude, ChatGPT and Perplexity connect by sign-in rather than by key: the owner approves a consent screen and the assistant receives a token prefixed `sat_`. The steps per assistant are on the [MCP server](/docs/mcp) page. Connected assistants, what each may do, and a revoke action live under Settings → Connected apps.

## Rate limits

Every credential gets 600 calls per minute and 10,000 per hour by default. A workspace or a single key can carry its own ceiling; the effective limit is the key's, else the workspace's, else the default.

When you exceed it the response is `429` with a `Retry-After` header in seconds. Traffic without a valid credential is limited separately by client address, so a burst of failed sign-ins never counts against your key.

## Lead privacy

Lead contact details are masked before they leave the workspace unless the owner turns masking off: names, emails, phone numbers and addresses come back with the first character and asterisks. The masking is applied identically to every lead tool.

## Errors

The MCP server speaks JSON-RPC and the REST API speaks plain JSON, but authentication failures look the same on both: the HTTP status below, and a `WWW-Authenticate` header your client can read. On REST the body is `{ "error": { "code": "unauthorized" } }` or `"forbidden"`; on MCP it is the JSON-RPC error shown.

| Situation | HTTP | Error |
| --- | --- | --- |
| No credential, or sent as a query parameter | 401 | `-32001` with a message saying to use the `Authorization: Bearer` header |
| Malformed or unknown credential | 401 | `-32001` "Invalid token format" |
| Revoked key or expired token | 401 | `-32001` |
| Tool needs a scope the credential lacks | 403 | error names the missing scope |
| Rate limit exceeded | 429 | `Retry-After` header, seconds until the window resets |

- Retry `429` after the header value, not before.
- Treat `401` as terminal for that credential: rotate the key or reconnect the assistant.

---
Source: https://app.streamagent.io/docs/authentication
