Developer docs / production render API

Give an agent a brief. Get back a finished video.

Future Video Studio exposes a production API for agentic video generation. Agents can submit screenplay-driven requests, upload supporting assets in the same formats supported by the studio, choose render parameters, and receive a completed signed video URL when the job finishes.

See request format
Account-scoped keysUser-default pipeline settingsReady-made MP4 output
API base
https://fmv-studio-frontend-t7cat7yhuq-uc.a.run.app/api/agent

Submit

POST /renders

Poll

GET /renders/{project_id}

Cancel

POST /renders/{project_id}/cancel

Authentication and billing

Keys belong to user accounts, not synthetic API wallets.

Managed API keys are created inside the product settings panel. Every render inherits the defaults and billing identity of the account that owns the key, which keeps model choices, stage behavior, and credit reservations aligned with the same production environment your team uses in the UI.

Supported inputs

Everything the studio already knows how to ingest.

  • Text-only briefs with screenplay, instructions, lore, style controls, and shot targets.
  • Uploaded image references for characters, environments, props, and mood boards.
  • Uploaded audio tracks for `uploaded_track` music workflows.
  • Uploaded video, PDF, and document assets using the same asset-analysis path as the studio UI.

Content type

`multipart/form-data`

  • `request_json` contains the render payload as a JSON string.
  • `files` can be repeated for image, audio, video, and document uploads.
  • `assets[]` inside the payload lets you label and classify those uploaded files.

Creative brief

  • `name`, `screenplay`, `instructions`, `additional_lore`
  • `visual_style_preset`, `visual_style_custom_instructions`
  • `project_mode`, `shot_count`, `scene_target_duration_seconds`

Model selection

  • `orchestrator_model`, `critic_model`
  • `image_model`, `image_resolution`
  • `video_model`, `video_resolution`
  • `music_model`, `stage_voice_briefs_enabled`

Music and timing

  • `music_workflow`, `lyrics_prompt`, `style_prompt`
  • `music_min_duration_seconds`, `music_max_duration_seconds`
  • `music_start_seconds`, `use_first_audio_asset_as_music`

Asset manifest

  • `assets[]` entries with `filename`, `label`, and `purpose`
  • Repeated `files` upload fields in the multipart form body
  • `wait_for_completion_seconds` if you want short blocking waits before polling

Reference payload

A complete request can be just one multipart POST.

request_json
{
  "name": "Archive corridor test",
  "project_mode": "scene",
  "screenplay": "Shot 1: A young woman enters a glowing archive corridor lined with suspended photographs. Shot 2: She reaches toward one moving photograph and the corridor bends into a luminous tunnel around her. Shot 3: She steps through the tunnel and arrives in a sunlit memory chamber as the photographs orbit overhead.",
  "instructions": "Create exactly three cinematic shots totaling about 24 seconds. Keep the subject visually consistent across all shots. Favor strong camera motion, realistic lighting, and clean transitions. No subtitles or text overlays.",
  "shot_count": 3,
  "scene_target_duration_seconds": 24,
  "image_resolution": "1K",
  "video_model": "veo-3.1-fast-generate-001",
  "video_resolution": "720p",
  "stage_voice_briefs_enabled": false,
  "wait_for_completion_seconds": 0
}
response
{
  "project_id": "proj_api_60c90c0841464675",
  "name": "Archive corridor test",
  "status": "completed",
  "current_stage": "completed",
  "is_running": false,
  "run_id": null,
  "final_video_url": "https://fmv-studio-frontend.../projects/proj_api_60c90c0841464675_final.mp4?...",
  "last_error": null,
  "asset_count": 1,
  "clip_count": 3,
  "status_url": "https://fmv-studio-frontend.../api/agent/renders/proj_api_60c90c0841464675",
  "cancel_url": "https://fmv-studio-frontend.../api/agent/renders/proj_api_60c90c0841464675/cancel"
}

Examples

Use the public app origin and poll until a signed video URL is ready.

Python
import json
import requests

BASE_URL = "https://fmv-studio-frontend-t7cat7yhuq-uc.a.run.app"
AGENT_KEY = "replace-with-your-managed-key"

request_payload = {
    "name": "Archive corridor test",
    "project_mode": "scene",
    "screenplay": "Shot 1: A young woman enters a glowing archive corridor lined with suspended photographs. Shot 2: She reaches toward one moving photograph and the corridor bends into a luminous tunnel around her. Shot 3: She steps through the tunnel and arrives in a sunlit memory chamber as the photographs orbit overhead.",
    "instructions": "Create exactly three cinematic shots totaling about 24 seconds.",
    "shot_count": 3,
    "scene_target_duration_seconds": 24,
    "video_model": "veo-3.1-fast-generate-001",
    "video_resolution": "720p",
    "stage_voice_briefs_enabled": False,
}

response = requests.post(
    f"{BASE_URL}/api/agent/renders",
    headers={"X-FVS-Agent-Key": AGENT_KEY},
    files={"request_json": (None, json.dumps(request_payload))},
    timeout=300,
)
response.raise_for_status()
job = response.json()

while True:
    status_response = requests.get(job["status_url"], headers={"X-FVS-Agent-Key": AGENT_KEY}, timeout=120)
    status_response.raise_for_status()
    status = status_response.json()
    if status["status"] == "completed":
        print("Video ready:", status["final_video_url"])
        break
    if status["status"] == "failed":
        raise RuntimeError(status.get("last_error") or "Render failed")
JavaScript
const form = new FormData();
form.append("request_json", JSON.stringify({
  name: "Archive corridor test",
  project_mode: "scene",
  screenplay: "Three-shot cinematic archive corridor sequence.",
  instructions: "Keep the lead visually consistent and total runtime near 24 seconds.",
  shot_count: 3,
  scene_target_duration_seconds: 24,
  video_model: "veo-3.1-fast-generate-001",
  video_resolution: "720p"
}));

const submit = await fetch("https://fmv-studio-frontend-t7cat7yhuq-uc.a.run.app/api/agent/renders", {
  method: "POST",
  headers: {
    "X-FVS-Agent-Key": "replace-with-your-managed-key"
  },
  body: form
});

const job = await submit.json();
const status = await fetch(job.status_url, {
  headers: {
    "X-FVS-Agent-Key": "replace-with-your-managed-key"
  }
}).then((res) => res.json());

Need higher-throughput access?

Talk to us about beta access and production integrations.

We can help with agent onboarding, multi-project usage, managed key rollout, and enterprise production workflows on top of the same API surface.

Terms