Framesail for agents
Framesail is the workflow and state layer for producing long-form video with AI: it owns the project database, asset continuity, voiceover timing, storyboard planning, and the render pipeline. Your agent drives the full workflow.
API & MCP access is included on the Pro and BYOK plans — see pricing.
Quickstart
The fastest path is claude.ai — zero config, no key handling:
1. Subscribe to Pro or BYOK (API & MCP access is plan-gated; the consent screen will tell you if your plan doesn't have it). 2. In claude.ai: Settings → Connectors → Add custom connector → https://api.framesail.com/mcp — a browser login opens; sign in and click Allow. 3. Verify: ask Claude "Am I connected to Framesail?" — the whoami tool reports your account and plan.
From there, your first pipeline run is a prompt away: "Create a Framesail project about <topic> and generate the script." For Claude Code instead, it's one command with an fsk_ key from your account page:
claude mcp add --transport http framesail \
https://api.framesail.com/mcp \
--header "Authorization: Bearer fsk_..."Everything below is the detail: the two surfaces, every client's connect config, how auth works under the hood, and the full pipeline workflow.
Surfaces
Two equivalent surfaces, one auth scheme. The MCP tools are thin wrappers over the same REST endpoints — pick one surface per pipeline run.
| Surface | URL | Best for |
|---|---|---|
| REST API | api.framesail.com | Scripts, SDKs, custom backends (OpenAPI at /openapi.json) |
| MCP server | api.framesail.com/mcp | Claude Code, Claude Desktop, claude.ai, Cursor, any MCP client |
Connecting
claude.ai / Claude Desktop / Claude mobile — no key needed
Settings → Connectors → Add custom connector → URL https://api.framesail.com/mcp. Claude opens a Framesail login in your browser — sign in, click Allow, done. The connection appears on your account page as an API key you can revoke anytime.
Claude Code / Agent SDK
claude mcp add --transport http framesail \
https://api.framesail.com/mcp \
--header "Authorization: Bearer fsk_..."Cursor
{
"mcpServers": {
"framesail": {
"url": "https://api.framesail.com/mcp",
"headers": { "Authorization": "Bearer fsk_..." }
}
}
}VS Code (Copilot agent mode)
{
"servers": {
"framesail": {
"type": "http",
"url": "https://api.framesail.com/mcp",
"headers": { "Authorization": "Bearer fsk_..." }
}
}
}Clients that support MCP OAuth can also omit the header entirely and connect to the bare URL — they'll pop the same browser login as claude.ai.
REST
Any HTTP client; the machine-readable spec lives at /openapi.json.
Authentication
Two ways in, one credential type underneath. OAuth login (claude.ai, Claude Desktop, any OAuth-capable MCP client): connect to the URL, sign in, approve — Framesail mints the credential for you. API keys (config-file clients, scripts, REST): create an fsk_ key on your account page (/app/account → API Keys) and send it as a Bearer token — the same header works for both REST and MCP:
Authorization: Bearer fsk_...Keys are shown once at creation and can be revoked anytime — OAuth connections show up in the same list, so revoking works identically. For security, key management itself requires a signed-in browser session — an API key cannot mint or revoke API keys. API & MCP access requires a Pro or BYOK subscription.
OAuth under the hood
For anyone implementing a client: it's spec-standard MCP authorization — OAuth 2.1 with Dynamic Client Registration (RFC 7591) and PKCE (S256 only). An unauthenticated request to /mcp gets a 401 with a WWW-Authenticate header pointing at the resource metadata (/.well-known/oauth-protected-resource/mcp), which advertises the authorization server; registration and token endpoints are in /.well-known/oauth-authorization-server. The access token the flow mints is a regular fsk_ key — same power, same revocation, visible on your account page. Anonymous initialize and tools/list are allowed so clients and directories can inspect the catalog before logging in; every tool call requires the token.
Connected but not sure it worked? The whoami tool (REST: GET /me) returns the account email and plan behind the credential — the cheapest possible sanity check.
BYOK — bring your own model keys
On the BYOK plan, any job whose model provider you supply a key for runs on your key and bills 0 credits. Two modes, usable together:
1. Stored (recommended): PUT /provider-keys/{provider} with {"key": "..."} — encrypted at rest (AES-256-GCM), never returned or logged, removable anytime.
2. Per-request: send X-Provider-Key-<provider> headers (e.g. X-Provider-Key-Openai: sk-...) on any request, including the MCP connection. For async jobs the key travels encrypted on the job row and is wiped the moment the job finishes.
Providers: openai, gemini, anthropic, fal (all video models), elevenlabs, minimax. Coverage is per-job: with only an OpenAI key, GPT script jobs are free (BYOK) while a Gemini storyboard bills credits. Each job's record notes which mode billed it.
The workflow
Every generation call returns 202 {"job_id": ...} immediately. Poll GET /jobs/status?project_id=... every 5–15s (jobs flow pending → running → complete | error). MCP clients should prefer the await_jobs tool — it long-polls server-side (~50s per call) so the agent doesn't burn turns. Long steps are normal: storyboard generation takes minutes, not seconds, and a full segment render longer — don't treat a slow job as a failed one.
Resuming / orientation: GET /projects/{id}/pipeline (MCP: get_pipeline_progress) returns every step's state plus a single next_action — call it when picking up an existing project or after any step, instead of inferring progress. State lives server-side; sessions can stop and resume freely.
| Step | REST | MCP tool |
|---|---|---|
| 0 · Pick a channel | GET /channels (create: POST /channels) | list_channels / create_channel |
| 1 · Create project | POST /projects | create_project |
| 2 · Script | POST /generate/script (or POST /script/save for your own); review via GET /script | generate_script / save_script / get_script / revise_script |
| 3 · Scan script | POST /generate/script_scan — extracts characters/environments/objects + voice blocks | scan_script / rescan_voice_blocks |
| 4 · Style templates | POST /generate/art_style_character_template + …_environment_template — the second half of style creation; reference images render against these, so finish both first | generate_style_template |
| 5 · Review assets | GET /assets, PATCH /assets/{id}, then POST /assets/{id}/generate-reference for recurring characters — rendered against the style templates | list_assets / update_asset / generate_asset_reference |
| 6 · Voiceover | Bind voices (PATCH /projects/{id}/voice, PATCH /assets/{id}/voice), then POST /generate/voice_block_batch | list_voices / set_narrator_voice / set_character_voice / generate_voiceover |
| 7 · Storyboard | Set the asset mix first (image vs video %, PATCH /projects/{id}) — the biggest cost lever; then POST /generate/storyboard | update_project / generate_storyboard |
| 8 · Render assets | The hard checkpoint: POST /segments/generate-all?dry_run=true, show the estimate, get a fresh yes — then for real | generate_segments / get_credit_balance |
| 9 · Polish (optional) | Music, SFX, captions | browse_audio_library / add_music_track / add_segment_sfx / update_caption_config |
| 10 · Build timeline | POST /scenes/build | build_scenes |
| 11 · Export MP4 | POST /projects/{id}/export | export_video |
| 12 · Download | GET /projects/{id}/export/download-url | get_video_url |
Steps are stateful — never fire step N+1 before step N's jobs are complete. Re-running scan_script deletes and recreates assets; after editing the script once assets are curated, use rescan_voice_blocks instead. After editing segments, regenerating assets, or changing music/captions, re-run build_scenes before export_video.
Styles & prompt overrides
Styles (channel-scoped) carry the creative identity: art_style, narrative_style, director_style, script_prompt, plus custom fields referenced as @field_name in prompts and resolved at generation time. Create styles from reference media (YouTube URLs, text, uploaded files) via POST /styles — or instantly from the curated preset catalog (GET /style-presets, MCP list_style_presets) with one preset per axis. Then bind one to a project with PATCH /projects/{id}/defaults.
Per-call prompt overrides: every generate endpoint accepts editable_sections: {section_id: content} — the same expert surface the web UI exposes. GET /jobs/{job}/template lists each job's sections, defaults, and which are locked. Don't rebuild prompts from scratch; override the one section you need.
Models: GET /models?job=... lists allowed models per job; the first entry is the default. Model choice matters — flash-tier models flatten storyboard pacing, so the defaults are the validated tier.
Etiquette & limits
- ·Poll every 5–15s; don't tight-loop. Rate limits: 50/min, 1000/hour per key on generation endpoints.
- ·Steps are stateful — never fire step N+1 before step N's jobs are
complete. - ·
dry_run=trueongenerate-allreturns asset count + credit estimate; use it before committing a large render. - ·Exports render on Framesail's infrastructure and are included in the plan (fair-use capped) regardless of BYOK.
Troubleshooting
| Symptom | What it means |
|---|---|
| 401 Unauthorized | The key is wrong, revoked, or missing. Create a fresh key on the account page, or reconnect the client to run the OAuth login again. Verify with whoami. |
| 403 Forbidden | The account's plan doesn't include API access — it's a Pro/BYOK capability. A downgrade disables existing keys. |
| 409 step_not_ready | A pipeline step was called before its prerequisites finished. The error's next_action names the exact call to make instead — don't retry the same one. |
| 409 job_already_running | That step is already in flight. await_jobs and re-check — re-calling never duplicates work or double-bills. |
| 402 Payment Required | Not enough credits for the operation. Check get_credit_balance, top up, or cover the job's provider with a BYOK key. |
| Slow job | Normal. Storyboards take minutes; a full segment render longer. Keep calling await_jobs while done=false — slow is not failed. |
Ready to connect? Generate a key on your account page, or review the Pro and BYOK plans.