Studio reference
This page documents Studio’s real surface: the HTTP endpoints the web app calls, the run lifecycle, and the environment that configures the service.
Authentication
Section titled “Authentication”The public API is session-authenticated through suite single sign-on. Browser requests carry the Studio session cookie established at GET /v1/sso/callback; the server validates it against identity and scopes every query to your workspace.
| Endpoint | Purpose |
|---|---|
GET /v1/sso/callback |
Redeems the SSO grant and sets the Studio session. |
GET /v1/auth/me |
Returns the signed-in account (id, email, name). |
POST /v1/auth/logout |
Clears the Studio session. |
Service-to-service callbacks live under /v1/controller/* and are gated by a shared controller secret — when that secret is unset, those routes return 404 and are invisible. They are used by Studio’s worker, not by you.
Health
Section titled “Health”| Endpoint | Purpose |
|---|---|
GET /healthz |
Cheap liveness check. Returns {"status":"ok"}. |
GET /readyz |
Dependency check (database + queue). Returns 200 when healthy, 503 (status: degraded) with per-check detail when not. |
Setup and capabilities
Section titled “Setup and capabilities”| Endpoint | Purpose |
|---|---|
GET /v1/setup/readiness |
What still needs connecting before Studio is fully usable in this workspace. |
GET /v1/features |
Which optional capabilities this deployment has enabled. |
GET /v1/blocks |
Browse-only catalog of text effects, transitions, VFX, stickers, and audio-reactive blocks. |
GET /v1/worker/status |
Whether the build queue is being drained — what the worker banner reads. |
Everything above is readable by any member. Changing the workspace brand (look, fonts, logo, voice, house format) and linking or unlinking the accounts Studio publishes with are workspace configuration and need the role owner or admin (admin_required). Creating and editing a template is a member’s work. See Roles and permissions.
Projects and variants
Section titled “Projects and variants”| Method & path | Purpose |
|---|---|
POST /v1/projects |
Create a project from a prompt. Creating it also enqueues the first build. |
GET /v1/projects |
List your workspace’s projects. |
GET /v1/projects/{id} |
Fetch one project. |
GET /v1/projects/{id}/current |
Fetch the project’s current version — the project-first read the editor opens with. |
PATCH /v1/projects/{id} |
Update a project. |
DELETE /v1/projects/{id} |
Delete a project. |
GET /v1/projects/{id}/variants |
List a project’s language variants. |
POST /v1/projects/{id}/variants |
Create a variant. |
One brand per workspace, used by every project and frozen onto each new run. Reading is open to members; every write is owner or admin (admin_required).
| Method & path | Purpose |
|---|---|
GET /v1/brand |
The brand: configured, theme or colours, fonts, voice, format (with format_detail), and the logo (logo_drive_file_id, a short-lived logo_url, logo_position, logo_scale). configured: false means the workspace never set one up. |
PATCH /v1/brand |
A merging patch: a key you send is set, a key you omit is left alone, null clears. Keys: theme, colours, fonts, voice, format, logo_position, logo_scale. A starter theme clears custom colours and vice versa; both in one patch is 422 brand_kit_invalid. Colours below the contrast bars are 422 brand_kit_illegible, naming the pair and ratio. {} records a configured brand with the stock look. |
POST / DELETE /v1/brand/logo |
Upload (multipart file, PNG/JPG/WebP/GIF up to 5 MB) or clear the watermark. |
Templates and assets
Section titled “Templates and assets”| Method & path | Purpose |
|---|---|
POST / GET /v1/templates |
Create or list templates. Each row carries its kind (visual or images) and project_count, the live number of projects using it; an images template also carries image_count and, when a picture is pinned, a short-lived preview_url. format is the kind of film the template makes (a house format key such as devotional); a template that sets a format or a style_preset beats the project’s own format, which beats the brand’s house format. format, style_preset and caption_style may be "" — follow the brand’s house format. caption_style is subtle, bold, pop, typewriter, typewriter-elegant or typewriter-large. verse_card is the card a typewriter caption quotes a verse on: light, glass, overlay, quote or lower; "" follows the format (devotional: glass). |
GET / PATCH / DELETE /v1/templates/{id} |
Fetch, update, or delete one. A template is a live preset and carries no brand: each new run reads it as it is then and freezes what it used, so an edit reaches every project on it from its next run. Deleting it leaves those projects with no template from their next run. |
POST /v1/templates/{id}/duplicate |
Copy a template as a starting point. |
POST / DELETE /v1/templates/{id}/background |
Upload or clear the template’s background (PNG, JPG, WebP or GIF, up to 5 MB). An images template answers 422 wrapper_not_supported here, and for intro/outro images and music. |
GET / POST /v1/templates/{id}/rules |
List or add rules that decide when parts of the template apply. A rule created without is_enabled is enabled. |
PATCH / DELETE /v1/templates/{id}/rules/{ruleId} |
Update or remove a rule. |
POST / GET /v1/assets |
Upload to, or list, the workspace asset library (images and audio, including music tracks). |
GET / DELETE /v1/assets/{id} |
Fetch or delete one asset. |
| Method & path | Purpose |
|---|---|
POST /v1/projects/{id}/runs |
Start a run. Accepts an optional language_codes array to fan out one run per language. Answers 422 conflicting_source_selectors when the project’s template sets a scene’s picture both in its pictures and in a rule. |
GET /v1/projects/{id}/runs |
List a project’s runs. |
GET /v1/projects/{id}/runs/{run_id} |
Fetch one run. |
POST /v1/projects/{id}/runs/{run_id}/cancel |
Cancel an in-flight run. |
POST /v1/projects/{id}/runs/{run_id}/retry |
Re-queue a failed or cancelled run. |
POST /v1/projects/{id}/runs/{run_id}/approve |
Approve a run — registers the video + thumbnail in Drive. |
GET /v1/runs/{run_id}/production |
Fetch the editable production document (scenes, image and audio URLs, render link, stale flag). |
POST /v1/runs/{run_id}/duplicate |
Clone a run into a different aspect ratio (reuses images, re-renders). |
PATCH /v1/runs/{run_id} |
Update a run’s label. |
DELETE /v1/runs/{run_id} |
Delete a run and its scenes, renders, and publishes. |
GET /v1/projects/{id}/artifacts/{run_id}/{step_index} |
Signed link to one pipeline step’s artifact. |
Changing aspect ratio
Section titled “Changing aspect ratio”Changing a finished video’s shape is a three-call flow, because a re-render is not free and you should see what it will cost before it starts.
| Method & path | Purpose |
|---|---|
POST /v1/runs/{run_id}/aspect-change/preflight |
What changing the aspect would do — the check the web app shows before you confirm. |
POST /v1/runs/{run_id}/aspect-change |
Start the change. |
POST /v1/runs/{run_id}/aspect-change/{op_id}/retry-preview |
Retry the preview render for an in-flight change. |
Multi-language fan-out
Section titled “Multi-language fan-out”POST /v1/projects/{id}/runs with a language_codes array creates a variant per code (the first becomes primary) and enqueues a run per variant in parallel. The response carries the created ids:
{ "run_ids": ["…", "…"], "variant_ids": ["…", "…"], "language_codes": ["en", "es"]}Omit language_codes and the single-run shape ({ "run_id": "…" }) is returned.
Run lifecycle
Section titled “Run lifecycle”A run advances through the pipeline and ends awaiting your approval:
queued → running → awaiting_approval → approvedA run can also reach failed or cancelled; both can be retried, which resets the run to queued and re-queues it.
Scenes and editing
Section titled “Scenes and editing”Once a run reaches awaiting_approval, its scenes are editable. The web app’s chat-driven editor calls these; each tool endpoint records an asynchronous operation you can poll.
| Method & path | Purpose |
|---|---|
POST /v1/runs/{run_id}/tools/regen_scene_image |
Regenerate one scene’s image. |
POST /v1/runs/{run_id}/tools/regen_all_images |
Regenerate every scene’s image. |
POST /v1/runs/{run_id}/tools/regen_scene_narration |
Re-voice one scene. |
POST /v1/runs/{run_id}/tools/regen_all_narration |
Re-voice every scene with a new voice. |
POST /v1/runs/{run_id}/tools/swap_voice |
Swap the narration voice. |
POST /v1/runs/{run_id}/tools/edit_script |
Edit the script. |
POST /v1/runs/{run_id}/tools/render_preview |
Render a fresh preview. |
POST /v1/runs/{run_id}/tools/bundle_render |
Render every aspect ratio at once as a bundle. |
POST /v1/runs/{run_id}/tools/set_video_style_preset |
Set the video’s style preset. |
POST /v1/runs/{run_id}/tools/set_video_vibe |
Apply a vibe bundle (style, transitions, effects) across the video. |
POST /v1/runs/{run_id}/tools/set_scene_vibe |
Apply a vibe bundle to one scene. |
GET /v1/tools/ops/{op_id} |
Poll an operation’s state. |
POST /v1/runs/{run_id}/tools/ops/{op_id}/retry |
Retry a failed operation. |
Studio also exposes finer-grained scene tools — text effects, transitions, VFX, stickers, audio-reactivity, and image-source policy (set_scene_image_source, set_video_image_source) — under the same /v1/runs/{run_id}/tools/* prefix, plus direct scene editing:
| Method & path | Purpose |
|---|---|
PATCH /v1/runs/{run_id}/scenes/{scene_id} |
Edit a scene field directly (e.g. duration). |
POST /v1/runs/{run_id}/scenes |
Insert a scene. |
DELETE /v1/runs/{run_id}/scenes/{scene_id} |
Delete a scene. |
POST /v1/runs/{run_id}/scenes/{scene_id}/duplicate |
Duplicate a scene. |
POST /v1/runs/{run_id}/scenes/reorder |
Reorder scenes. |
POST /v1/runs/{run_id}/scenes/{scene_id}/image |
Upload your own image for a scene. |
POST /v1/runs/{run_id}/scenes/{scene_id}/image-from-url |
Use an image from a URL for a scene. |
POST /v1/runs/{run_id}/scenes/transitions |
Set the transition on every scene at once. |
POST /v1/runs/{run_id}/scenes/durations |
Set the duration on every scene at once. |
POST /v1/runs/{run_id}/scenes/{scene_id}/lock / DELETE …/lock |
Lock a scene against regeneration. |
POST /v1/runs/{run_id}/rollback |
Revert the scene changes from a prior operation. |
Run-level assets and exports
Section titled “Run-level assets and exports”| Method & path | Purpose |
|---|---|
PUT /v1/runs/{run_id}/music/asset |
Attach a track from the asset library as the background music. |
PATCH / DELETE /v1/runs/{run_id}/music |
Adjust the music volume against the narration, or clear the track. |
POST / PATCH / DELETE /v1/runs/{run_id}/logo |
Set, reposition, or clear a logo watermark. |
GET /v1/runs/{run_id}/renders |
List a run’s renders, newest first. |
GET /v1/runs/{run_id}/captions.srt |
Export SubRip captions. |
GET /v1/runs/{run_id}/transcript.json |
Export a structured transcript. |
POST / DELETE /v1/runs/{run_id}/share |
Mint or clear a public share link. |
GET /v1/share/{token} |
Public, token-authenticated view of a shared run. |
POST /v1/runs/{run_id}/webhook/test |
Fire a test payload at the run’s configured webhook URL. |
Voices
Section titled “Voices”Studio proxies voice listing and previews so the web editor doesn’t need a separate Text-to-Speech session:
| Method & path | Purpose |
|---|---|
GET /v1/voices |
List the voices available to the workspace. |
GET /v1/voices/{voice_id}/preview |
Stream a voice preview sample. |
When no voice is chosen, Studio resolves the workspace default (Aria).
Chat and conversations
Section titled “Chat and conversations”| Method & path | Purpose |
|---|---|
POST /v1/chat |
The chat home — an NDJSON stream. |
POST /v1/chat/resume |
Resume a turn that paused for your approval. |
GET /v1/conversations |
List saved conversations. |
GET /v1/conversations/{id}/messages |
Page one conversation’s history. |
PATCH / DELETE /v1/conversations/{id} |
Rename or delete a conversation. |
GET / POST /v1/runs/{run_id}/messages |
Read or append the per-video editor chat. |
POST /v1/runs/{run_id}/chat/production |
The production agent turn for a video. |
Publishing
Section titled “Publishing”Publishing to social channels is wired and workspace-scoped. It targets the social accounts you’ve connected in Connect. A video must be approved and have a render before it can be published.
| Method & path | Purpose |
|---|---|
POST /v1/runs/{run_id}/publish |
Schedule or immediately publish to one or more connected social accounts. |
GET /v1/runs/{run_id}/publishes |
List a video’s publish records and their state. |
GET /v1/renders/{render_id}/publishes |
List publishes for one specific render. |
Supported channels: YouTube, TikTok, Instagram, Facebook, Threads, LinkedIn. Automatic retries are capped at four attempts (backing off roughly 2, 10, and 30 minutes) and only apply to failures that occur before anything reaches the platform — once the upload has started, the attempt is terminal so a retry can never produce a second public post.
From a GitHub repo
Section titled “From a GitHub repo”| Method & path | Purpose |
|---|---|
POST /v1/source/github |
Turn a repo URL into a project and its first build. Body: { "repo_url": "https://github.com/owner/repo", "workspace_id": "…", "workspace_slug": "…" }, plus the optional language_codes, aspect_ratio, and voice fields the prompt path accepts. |
The GitHub credential is resolved per request from Connect, scoped to workspace_slug. Public repositories work with no connection; to read private repositories, connect GitHub in Connect for the workspace. Error mapping: an unknown repo returns 404; a GitHub or credential-lookup failure returns 502; an unparseable URL returns 400.
Saved promos
Section titled “Saved promos”| Method & path | Purpose |
|---|---|
GET /v1/promos |
List saved promo compositions for the workspace. |
GET /v1/promos/{id} |
Fetch a saved promo with fresh signed URLs. |
Configuration
Section titled “Configuration”Studio runs as two processes — an HTTP API and a background worker — plus a web front end. Video rendering happens on Studio’s own internal render backend; it is not a separate product and there is nothing for you to sign into or configure for it. The variables below configure the two Studio processes.
API service
Section titled “API service”| Variable | Purpose | Default |
|---|---|---|
STUDIO_API_ADDR |
API listen address | :9104 |
STUDIO_DATABASE_URL |
Postgres DSN (schema studio) |
unset → database-backed routes fail until set |
STUDIO_REDIS_URL |
Job queue connection | redis://localhost:6379/4 |
STUDIO_IDENTITY_API_URL |
Identity host for SSO | http://localhost:9091 |
STUDIO_WEB_URL |
Post-SSO redirect target | http://localhost:4332 |
STUDIO_WEB_URL_ALLOWLIST |
Allowed post-redeem redirect origins (comma-separated) | unset |
STUDIO_CORS_ALLOWED_ORIGINS |
Permitted request origins (comma-separated) | unset |
IDENTITY_CONTROLLER_SECRET |
Bearer for /v1/controller/* callbacks |
unset → controller routes return 404 |
TTS_API_URL |
Text-to-Speech host (voice proxy) | http://localhost:9098 |
CHAT_API_URL |
Chat host | http://localhost:9102 |
CONNECT_API_URL |
Connect host (per-workspace credentials) | http://localhost:9105 |
GITHUB_API_URL |
GitHub REST base (override for GitHub Enterprise) | https://api.github.com |
DRIVE_API_URL |
Drive host (artifact registration) | http://localhost:9106 |
SUITE_TOOL_SECRET |
Bearer shared with Drive | unset → Drive registration disabled |
Worker service
Section titled “Worker service”The worker drains the job queue and runs the pipeline. In addition to the shared STUDIO_REDIS_URL, STUDIO_DATABASE_URL, and peer-service URLs above, it reads:
| Variable | Purpose |
|---|---|
STUDIO_API_URL |
Callback base to the API |
IMAGEGEN_API_URL |
Image-generation host |
STUDIO_STOCK_ENABLED |
Kill switch for stock-photo lookup (default on) |
STUDIO_CACHE_DIR |
Local cache directory |
STUDIO_IMAGEGEN_POLL_TIMEOUT / STUDIO_RENDER_POLL_TIMEOUT / STUDIO_TTS_POLL_TIMEOUT / STUDIO_JOB_TIMEOUT |
Per-step and per-job timeouts |
Migrations
Section titled “Migrations”Studio’s schema lives in the studio Postgres schema. Apply migrations with the bundled command, which reads STUDIO_MIGRATE_DATABASE_URL (falling back to STUDIO_DATABASE_URL):
cd apps/studio/api && go run ./cmd/migrate upLocal development
Section titled “Local development”# From the suite root — start the database, queue, and object store first:make dev-db
# Then, in separate shells:make dev-studio-api # HTTP API on :9104make dev-studio-worker # pipeline workermake dev-studio-web # web app on :4332
# Health check:curl -s http://localhost:9104/healthz# => {"status":"ok"}The worker calls peer services (Chat, Text-to-Speech, Image generation). Start the ones you need with their own make dev-* targets.