Developer docs
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.
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"}'curl https://app.streamagent.io/api/v1/workspace \
-H "Authorization: Bearer sa_live_…"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 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, actions:direct |
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, comments, questions & Shorts |
videos:write | Add and update your videos | Add or generate 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, route results, traffic, pixels, ads & goals |
transcripts:read | Search your video transcripts | Full transcripts & moment search |
routes:read | View your routes | Flows, steps & branches, Smart Rotations & landing pages |
routes:write | Create and edit your routes | Build flows, steps & branches |
workspace:read | View your workspace settings | Plan, usage, tags, brand voice, team, settings, domains & integrations |
channel:write | Curate your main page and collections | Collections, what they hold, and your main page |
outcomes:read | View your revenue outcomes | Purchases, booked calls & refunds with value, and revenue sources |
workspace:manage | Manage webhooks and API keys | Endpoints, secrets, delivery log & keys |
actions:direct | Act without your approval | Book calls, archive or pause, generate clips, curate collections, rename tags & edit Studio projects at once instead of suggesting them |
Some writes wait for approval: book_call, archiving with update_video, pausing or archiving with update_route, generate_video, the channel curation tools, rename_tag and edit_studio_project. Without actions:direct a call to any of them is saved as a suggestion the workspace owner applies in the app (Settings → Changes → Suggestions): the tool returns proposed: true with the proposal_id, and over REST the status is 202. Nothing is applied until a member clicks Apply. actions:direct is never issued by default -- a sign-in connection must request it and the owner approves it on the consent screen; among keys only the Admin tier carries it.
Every write a credential makes is listed for the owner under Settings → Changes, labelled "Connected app", with Undo wherever the change can be reversed.
One key across every client
An Enterprise agency can create a key from its own workspace that reaches every client workspace under it: tick Every client workspace when creating it under Settings → API keys (or pass agency_wide: true to POST /api-keys with an Admin key from the agency workspace). The key keeps its tier; what changes is which workspace a request acts on. Name the client on each request with the X-StreamAgent-Workspace header, as its id or its handle (the {handle}.streamagent.io part). Without the header the key acts on the agency workspace itself.
curl https://app.streamagent.io/api/v1/leads \
-H "Authorization: Bearer sa_live_…" \
-H "X-StreamAgent-Workspace: acme-realty"GET /workspaces (the list_workspaces tool) returns the agency and every client with the ids and handles the header accepts. A header naming a workspace outside the agency, or sent with a key that is not agency-wide, is refused with 403 before anything is read. Every call is logged under the workspace it acted on, so each client's Connected apps feed shows what the agency's key did there. The MCP server takes the same header on its HTTP requests, so an assistant configured with one key can be pointed at one client.
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 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; Enterprise workspaces get 2,000 per minute and 50,000 per hour. A workspace or a single key can carry its own ceiling; the effective limit is the key's, else the workspace's, else the plan'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
429after the header value, not before. - Treat
401as terminal for that credential: rotate the key or reconnect the assistant.