Developer docs
REST API
Plain JSON over HTTPS for everything the MCP server can do. Every route below is also an MCP tool of the same name: one implementation, one scope map, one rate limit, reachable from curl, a cron job or an automation platform.
Conventions
| Item | Rule |
|---|---|
| Base URL | https://app.streamagent.io/api/v1 |
| Authentication | Authorization: Bearer sa_live_… with an API key, or a sat_ assistant token. See Authentication. |
| Content | JSON in, JSON out. Send Content-Type: application/json on writes. |
| Ids | UUID strings, exactly as the list routes return them. Never construct one. |
| Versioning | The version is in the path. This version only gains fields and routes; a breaking change would be a new path. |
| Rate limits | The same per-credential ceilings as the MCP server, with Retry-After on 429. |
| Lead privacy | Lead fields are masked exactly as on the MCP server when the workspace keeps masking on. |
curl "https://app.streamagent.io/api/v1/leads?status=new&limit=20" \
-H "Authorization: Bearer sa_live_…"curl -X POST https://app.streamagent.io/api/v1/routes \
-H "Authorization: Bearer sa_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: onboarding-route-2026-09" \
-d '{"entry_video":"Welcome tour","name":"Onboarding"}'Pagination
List routes take limit (default 50, at most 100) and cursor. The response carries a pagination block with total, limit, has_more and next_cursor; pass next_cursor back as cursor until it is null. Cursors are opaque and only valid for the same route and filters.
{
"leads": [ … ],
"pagination": { "total": 143, "limit": 50, "has_more": true, "next_cursor": "eyJvIjo1MH0" },
"pii_redacted": true
}Idempotent writes
Send an Idempotency-Key header (any string up to 255 characters, unique per operation) on a write and the first response is stored for 24 hours. A retry with the same key and the same request gets that response back with Idempotency-Replayed: true; the same key with a different request is a 409 conflict. Keys are private to the credential that sent them.
Errors
Every non-success response is { "error": { "code", "message", "details"? } }. The message is written to be shown to a developer and lists every problem it found, so one fix reaches a correct call.
| Code | HTTP | Meaning |
|---|---|---|
unauthorized | 401 | No credential, or one that is malformed, revoked or expired. The response carries a WWW-Authenticate header. |
forbidden | 403 | The credential is valid but lacks the scope the route needs; details.required_scope names it. |
plan_limit | 403 | The workspace plan does not include this capability; details.entitlement names it. |
not_found | 404 | No route at that path, or the object id is not in this workspace. |
method_not_allowed | 405 | The path exists but not for that verb. The Allow header lists the verbs that work. |
conflict | 409 | An Idempotency-Key was reused with a different request, or the first request with it is still running. |
invalid_request | 400 | A parameter or body field is missing, unknown or the wrong shape; the message lists every problem at once. |
rate_limited | 429 | Over the per-credential ceiling. Retry after the number of seconds in Retry-After. |
internal | 500 | Something failed on our side. The details are logged; retry once, then contact support. |
- Retry
429after the header value and500once; never retry400,401,403or409unchanged. - A
404on an id means the object is not in this workspace, which is also what a wrong workspace key looks like.
Machine-readable contract
The full OpenAPI document, generated from the same source as this page, is at /api/v1/openapi.json. Point a client generator or an assistant at it.
Routes
Grouped as on the MCP server page. Required parameters are marked with *. Path segments in braces are ids from the list routes; GET routes take parameters in the query string, other verbs in a JSON body.
Outcomes in one call
| Method and path | What it does | Scope | Query or body fields |
|---|---|---|---|
GET /leads/call-list | Your hottest open leads, why each one matters now, and the next step for each. | leads:read | limit |
GET /results | Plays to leads to calls to revenue for a window, against the one before. | outcomes:read | window |
POST /videos/{video_id}/route-plan | Plan a lead-capturing StreamRoute from one video, saved as a suggestion to approve. | routes:write | — |
POST /rotations/plan | Describe who goes where in one sentence; get the lanes, saved as a suggestion to approve. | routes:write | brief* |
Suggestions
| Method and path | What it does | Scope | Body fields |
|---|---|---|---|
POST /proposals | Save a change as a suggestion card you approve in the app; nothing changes until you click Apply. | workspace:read | action*, params*, rationale |
POST /proposals/plans | Save two to eight related changes as one card; Apply runs them in order and Undo reverses all. | workspace:read | title*, steps*, rationale |
GET /proposals/actions | The changes a suggestion can carry, with their params. | workspace:read | — |
Videos
| Method and path | What it does | Scope | Query or body fields |
|---|---|---|---|
GET /videos | Browse your library with status and view counts. | videos:read | status, folder_id, tags, search, sort, limit, cursor |
GET /videos/{video_id} | Full detail and stats for one video. | videos:read | — |
GET /embed | The code or site-builder prompt that puts a video, route or rotation on a website. | videos:read | video_id, route_id, rotation_id |
POST /videos/compare | Rank videos on real performance, not raw views. | videos:read | video_ids* |
GET /videos/{video_id}/key-moments | The notable moments detected in a video. | videos:read | — |
PATCH /videos/{video_id} | Rename, describe, or retag a video (write); archiving needs approval unless granted. | videos:write | title, description, tags, archived |
POST /videos | Pull a video file in from a public link; it processes in the background (write). | videos:write | source_url*, title, folder_id, tags |
POST /videos/uploads | Create the video and get a one-time URL to send the file to (write). | videos:write | file_name*, file_size*, title, folder_id, tags |
POST /videos/generate | Render a clip with a connected AI video tool and add it to the library (write). | videos:write | provider*, prompt, script, model, avatar_id, voice_id, aspect_ratio, image_url, duration, folder_id |
GET /videos/generations/{generation_id} | Where a generation is: rendering, added to the library, or why it stopped. | videos:read | — |
GET /videos/generation-options | Which AI video tools are connected and the models, avatars and voices they offer. | videos:read | provider |
POST /studio/projects/{project_id}/edit | Clean up, cut, arrange clips, set sound, music, text and captions (write); needs approval unless granted. | videos:write | doc_version*, ops*, rationale |
GET /comments | Recent comments on your videos, and which ones are hidden. | videos:read | video_id, limit |
GET /videos/{video_id}/questions | What viewers asked a video, answered or not. | videos:read | only_unanswered |
GET /shorts | Suggested and made Shorts, with this month’s allowance. | videos:read | video_id |
GET /folders | Your video and route folders. | videos:read | kind |
GET /studio/projects | Your StreamAgent Studio projects and their takes. | videos:read | — |
GET /studio/projects/{project_id} | One project’s timeline, sound, music, scenes, cameras and what Clean up would cut. | videos:read | — |
Analytics
| Method and path | What it does | Scope | Query parameters |
|---|---|---|---|
GET /videos/{video_id}/analytics | Views, engagement, and conversion for a video. | analytics:read | from_date, to_date |
GET /videos/{video_id}/retention | Where viewers stay and where they drop off. | analytics:read | — |
GET /changes | What changed across your workspace lately. | analytics:read | days |
GET /analytics/summary | The workspace numbers for a range, each with its prior-period change. | analytics:read | range |
GET /analytics/daily | A per-day series between two dates. | analytics:read | from, to |
GET /routes/{route_id}/performance | How many reach each step of a route, where it loses people, and its leads. | analytics:read | — |
GET /goals | This month’s targets for leads, views and depth, with the pace. | analytics:read | — |
GET /meta/ads | Spend, leads and cost per lead for ads launched from StreamAgent. | analytics:read | days |
GET /pixels | Conversions sent to each ad pixel, and any that failed. | analytics:read | days |
GET /traffic | Where viewers come from: sources, devices and countries. | analytics:read | days |
GET /ai-search | Whether AI assistants cite your videos, by question and engine. | analytics:read | days |
Outcomes
| Method and path | What it does | Scope | Query parameters |
|---|---|---|---|
GET /outcomes | The revenue ledger: purchases, booked calls and refunds with value. | outcomes:read | from_date, to_date, kind, status, lead_id, video_id, limit, cursor |
GET /outcomes/sources | Which revenue sources are connected and when each last reported. | outcomes:read | — |
Provisioning
| Method and path | What it does | Scope | Query or body fields |
|---|---|---|---|
GET /webhook-endpoints | Every endpoint with its events and whether it is active. | workspace:manage | — |
POST /webhook-endpoints | Register a URL and get its signing secret once (write). | workspace:manage | name*, url*, events, include_clients |
PATCH /webhook-endpoints/{endpoint_id} | Rename, re-point, change events, pause or rotate the secret (write). | workspace:manage | name, url, events, active, include_clients, rotate_secret |
DELETE /webhook-endpoints/{endpoint_id} | Remove an endpoint and its history (write). | workspace:manage | — |
POST /webhook-endpoints/{endpoint_id}/test | Deliver the synthetic test event and report the result (write). | workspace:manage | — |
GET /webhook-endpoints/{endpoint_id}/deliveries | What was sent to an endpoint and how it went. | workspace:manage | status, limit, cursor |
GET /api-keys | Active keys by name, prefix and tier. | workspace:manage | — |
POST /api-keys | Mint a key of equal or lower access and receive it once (write). | workspace:manage | name*, scope, agency_wide |
DELETE /api-keys/{key_id} | Stop a key immediately (write). | workspace:manage | — |
Leads
| Method and path | What it does | Scope | Query or body fields |
|---|---|---|---|
GET /leads | Your captured leads, most engaged first. | leads:read | video_id, status, source, from_date, to_date, search, sort, limit, cursor |
GET /leads/{lead_id} | One lead with full activity history. | leads:read | — |
GET /leads/{lead_id}/journey | A lead’s complete timeline across your videos. | leads:read | — |
PATCH /leads/{lead_id} | Set status, tags, or append a note (write). | leads:write | status, tags, notes, email, name, phone |
PUT /leads | Add a lead by email, or enrich the one that already exists (write). | leads:write | email*, first_name, last_name, name, phone, status, tags, notes, custom_fields, source |
GET /leads/export | A private, hour-long link to the Leads page CSV, when lead details are not masked. | leads:read | status, video_id, search, heat, date_from, date_to, booked, rewatcher |
Transcripts
| Method and path | What it does | Scope | Query parameters |
|---|---|---|---|
GET /transcripts/search | Find where a topic is spoken across your library. | transcripts:read | q*, video_id, limit |
GET /videos/{video_id}/transcript | The full transcript for a video. | transcripts:read | offset, max_chars |
Routes
| Method and path | What it does | Scope | Query or body fields |
|---|---|---|---|
GET /routes | Your interactive routes. | routes:read | video_id, status, limit, cursor |
GET /routes/{route_id} | The structure of one route. | routes:read | — |
PATCH /routes/{route_id} | Rename a route (write); pausing or archiving needs approval unless granted. | routes:write | name, status, available_from, available_until, description |
POST /routes | Start a new interactive route (write). | routes:write | entry_video*, name |
POST /routes/{route_id}/steps | Add a video step to a route (write). | routes:write | video* |
POST /routes/{route_id}/branches | Wire the choices between steps (write). | routes:write | question, branches* |
GET /landing-pages | Your landing pages with status, views and leads. | routes:read | — |
GET /landing-pages/{landing_page_id} | Everything on one landing page, section by section. | routes:read | — |
GET /rotations | Each rotation with its lanes, live tests and how they are doing. | routes:read | include_archived |
Scheduling
| Method and path | What it does | Scope | Query or body fields |
|---|---|---|---|
GET /bookings | Upcoming and past calls booked through your videos. | leads:read | scope, limit, cursor |
GET /scheduling/overview | Your calendar shape at a glance. | workspace:read | — |
GET /scheduling/availability | Why a slot is (or isn’t) offered. | workspace:read | event_type |
POST /bookings | Book a call and capture the lead (write); needs approval unless granted. | leads:write | event_type_id*, start*, invitee_email*, invitee_name, invitee_phone, invitee_timezone |
GET /scheduling/slots | The times an event type actually offers next. | workspace:read | event_type, days |
Main page & collections
| Method and path | What it does | Scope | Body fields |
|---|---|---|---|
GET /channel | What your main page shows, and every collection. | workspace:read | — |
GET /collections/{collection_id} | One collection and what’s in it. | workspace:read | — |
POST /collections | A new public page of chosen videos (write); needs approval unless granted. | channel:write | title*, dek, slug, fill_rule, rule_folder_id, rule_tag, listed_on_home, items, video_id, route_id |
PATCH /collections/{collection_id} | Title, intro, address and how it fills (write); needs approval unless granted. | channel:write | title, dek, slug, fill_rule, rule_folder_id, rule_tag, listed_on_home |
DELETE /collections/{collection_id} | Take a collection’s page down (write); needs approval unless granted. | channel:write | — |
POST /collections/{collection_id}/items | Put videos and routes in a collection, or take them out (write); needs approval unless granted. | channel:write | items*, in* |
PUT /collections/{collection_id}/featured | Choose what leads a collection’s page (write); needs approval unless granted. | channel:write | video_id, route_id |
PATCH /channel | What your main page shows and how it reads (write); needs approval unless granted. | channel:write | collection_id, headline, dek, tagline, cta_route_id, cta_label, website_url, enabled |
Workspace
| Method and path | What it does | Scope | Query or body fields |
|---|---|---|---|
GET /workspace | Plan, usage, and the guidance you wrote for assistants. | workspace:read | — |
GET /workspaces | The workspaces this credential can act on; an agency-wide key lists every client. | workspace:read | — |
GET /tags | The tags in use across your content. | workspace:read | — |
POST /tags/rename | Rename or merge a tag everywhere it’s used (write); needs approval unless granted. | videos:write | tag*, new_tag*, applies_to |
GET /search | One search across videos, transcripts, routes, and leads. | workspace:read | q* |
GET /team | Who is on the team, their roles, and seats left. | workspace:read | — |
GET /domains | Each connected domain and whether it is live. | workspace:read | — |
GET /workspace/settings | Name, caption language, discoverability, AI access and brand voice. | workspace:read | — |
GET /integrations | Which apps are connected and whether each is healthy. | workspace:read | provider |
GET /meta | Whether Meta is connected, the ad account and pixel, and audience sync. | workspace:read | — |
GET /leads/routing | The rules that hand new leads to teammates, in the order they run, with the fields a rule can use. | leads:read | — |
GET /playbooks | An agency’s saved playbooks and the client workspaces they can be deployed into. | workspace:read | — |
GET /routes/{route_id}/partners | A route’s partners with their links and ledger: leads, sales, revenue and owed. | routes:read | days |
GET /meta/promote/options | What a Meta ad can use: Pages, audiences, currency and budget bounds, and the ads already running for a video or route. | workspace:read | source_type, source_id |
GET /agent/usage | This month’s agent messages: used, left, and when they reset. | workspace:read | — |
GET /agency/overview | Every client workspace with its numbers, health flags and waiting suggestions. | analytics:read | window |
POST /domains/{domain_id}/check | Check a custom domain’s DNS now; it goes live when the record is right. | workspace:read | — |
Not in this version
Deleting a video or a lead stays a signed-in action; archive is the reversible path and is on PATCH /videos/{video_id}.