{"openapi":"3.1.0","info":{"title":"Vocal Video API v2","version":"2.0.0","description":"The Vocal Video API v2 is a **tool-shaped** surface: every endpoint is a\nsingle `POST /api/v2/tools/{name}` whose JSON body *is* the tool's input.\nThe same 57 tools (20 read, 37 write) back the in-app\nAI assistant and the [MCP server](/docs/mcp), so behavior is identical\nacross surfaces. To use these tools from Claude or ChatGPT rather than\nfrom code, see [Connect Claude](/docs/guides/connect-claude).\n\n**Authentication.** Pass a workspace API key as `Authorization: Bearer \u003ckey\u003e`\n([create one in Settings → API keys](https://vocalvideo.com/app/api_keys)). Read-scoped keys\nmay call read tools only; write-scoped keys may call any tool. API access must be\nenabled for the account.\n\n**Limits.** Tool responses are capped at 256 KB; an\noversize read result returns 413 with a hint toward a lighter variant where one exists.\nAn oversize successful write returns a compact success result instead, because the\nmutation has already committed; inspect the resource with a read tool before retrying.\n"},"servers":[{"url":"https://vocalvideo.com"}],"tags":[{"name":"Read tools","description":"Non-mutating tools. Callable by read- and write-scoped keys."},{"name":"Write tools","description":"State-changing tools. Require a write-scoped key."}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Workspace API key. [Create one in Settings → API keys](https://vocalvideo.com/app/api_keys)."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string"},"details":{"type":"array","items":{"type":"string"}}}}}}}},"paths":{"/api/v2/tools/get_account_usage":{"post":{"operationId":"get_account_usage","summary":"get account usage","description":"Read the workspace account's current usage and allowances. Use it before kicking off metered work so you can tell the user they are close to a limit instead of failing at write time. Three separate meters, never interchangeable — say which one you mean: `publishes_remaining` (videos publishable this month; absent means the plan is unlimited), `video_requests_remaining` of `video_requests_per_period` (invitations the account may send), and `ai_credits_remaining` of `ai_credits_granted` (AI effects, AI templates, collector translation, and your own replies — every run you make spends these). `ai_credits_renew` is false when the grant is one-time rather than refilling each term. Also returns `collector_count`, `response_count`, `video_count`, and `gallery_count` — the authoritative totals, matching what the user sees in the app. Answer any \"how many do I have\" question from these; the `list_*` tools return ranked shortlists, not totals.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_workspace_brand":{"post":{"operationId":"get_workspace_brand","summary":"get workspace brand","description":"Read the workspace's brand surface: brand name, domain, default theme / aspect ratio / visibility, storyboard and collector colors, and the font ids the storyboards inherit by default. Use this when the user asks about brand alignment, when you need to pick colors that match the rest of their work, or before showing design previews.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_account_features":{"post":{"operationId":"get_account_features","summary":"get account features","description":"Read the workspace account's plan-tier capability flags: pro features, premium themes, custom domain, custom fields, custom release, kiosk mode, downloads, API access, watermark control. Use this to decline gracefully when the user asks for a feature their plan doesn't include — surface the capability gap rather than trying and failing.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/list_collectors":{"post":{"operationId":"list_collectors","summary":"list collectors","description":"Find collectors (video request campaigns) in the user's workspace. Returns a shortlist with status, response count, and last-reply recency. Use this for \"show me my collectors\", \"find my hiring collector\", or to pick a collector before reading its prompts / sending invitations. Results carry `returned` (rows in this payload), `matched` (hits for the filters you sent — NOT a workspace total), and `truncated`. When `truncated` is true, narrow the filters rather than assuming you saw everything.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Full-text search across nickname and title."},"status":{"type":"string","enum":["active","inactive"],"description":"`active` covers collectors currently accepting responses (including freshly-initialized ones); `inactive` covers paused collectors. Omit for both. Archived collectors are never returned."},"starred":{"type":"boolean","description":"If true, return only starred collectors."},"since_days":{"type":"integer","description":"Restrict to collectors created in the last N days."},"sort":{"type":"string","enum":["newest","oldest","abc","most_replies"],"description":"`newest` (default) by creation recency, `oldest` reverses it, `abc` orders alphabetically by nickname, `most_replies` by response count descending."},"limit":{"type":"integer","default":20,"maximum":50,"description":"Max results to return."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_collector":{"post":{"operationId":"get_collector","summary":"get collector","description":"Fetch a single collector by id. Returns the same payload as a `list_collectors` entry plus the prompts list (in display order — the questions respondents see), the welcome / thank-you copy, and the invitation / reminder email copy. Use this before any mutation tool that targets a collector's prompts, welcome video, or distribution.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Collector id from list_collectors."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/create_collector":{"post":{"operationId":"create_collector","summary":"create collector","description":"Create a new collector (video request campaign). Pass `ai_prompt` with a description of what you want to ask (e.g., \"hiring videos about why people love working at Acme\") and `intended_usage` so the brand-aware generator (Agent::CollectorGenerator) can seed tailored prompts and copy. Without `ai_prompt`, returns an empty collector you can populate with `add_prompt`. The collector is set to active and ready to accept responses immediately. Calling this makes the new collector the conversation's subject, which is what puts the tools that edit its questions and copy in reach — they arrive with the user's next message, not this one.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ai_prompt":{"type":"string","description":"Plain-language description of what you want to collect. The generator seeds prompts + copy from this."},"intended_usage":{"type":"string","enum":["testimonials","employee","hiring","communication","learning","other"],"description":"Picks which generator template to use. Defaults to the account's primary signup usage."},"nickname":{"type":"string","description":"Workspace-only label for the collector.","maxLength":191},"title":{"type":"string","description":"Public-facing title shown to respondents.","maxLength":191}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/update_collector":{"post":{"operationId":"update_collector","summary":"update collector","description":"Update one or more copy fields on a collector — nickname, title, intro (welcome blurb), finish_headline / finish_body (thank-you screen), contact_name / contact_title (the in-app spokesperson), sender_name (the From-name on invitations), and the invitation / reminder email copy (subject, body, cta). Also toggles show_logo (the workspace logo on the public collector pages), auto_assemble_drafts (assemble a draft video from every new response automatically), and template_id (which workspace template those drafts assemble with). Use for \"rename my hiring collector\", \"change the thank-you message\", \"reword the invitation email\", \"hide our logo\", \"auto-build drafts with our Spotlight template\", etc. Pass only the fields that change.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["collector_id"],"properties":{"collector_id":{"type":"integer"},"intended_usage":{"type":"string","enum":["testimonials","employee","hiring","communication","learning","other"],"description":"Re-point the collector's purpose (testimonials / employee / hiring / communication / learning / other)."},"nickname":{"type":"string","maxLength":191},"title":{"type":"string","maxLength":191},"intro":{"type":"string","description":"Public-facing welcome blurb shown to respondents."},"finish_headline":{"type":"string","description":"Thank-you screen headline shown after recording.","maxLength":191},"finish_body":{"type":"string","description":"Thank-you screen body shown after recording."},"contact_name":{"type":"string","description":"Workspace contact name (the person fronting the request).","maxLength":191},"contact_title":{"type":"string","description":"Workspace contact title.","maxLength":191},"sender_name":{"type":"string","description":"Display name used as the From-name on invitation emails.","maxLength":191},"invitation_subject":{"type":"string","description":"Subject line of the invitation email.","maxLength":191},"invitation_body":{"type":"string","description":"Body copy of the invitation email."},"invitation_cta":{"type":"string","description":"Call-to-action button label on the invitation email.","maxLength":191},"reminder_subject":{"type":"string","description":"Subject line of the reminder email.","maxLength":191},"reminder_body":{"type":"string","description":"Body copy of the reminder email."},"reminder_cta":{"type":"string","description":"Call-to-action button label on the reminder email.","maxLength":191},"show_logo":{"type":"boolean","description":"Whether the workspace logo appears on the collector's public pages. Set false to hide it."},"template_id":{"type":["integer","null"],"description":"Workspace template id (from list_templates) this collector's drafts assemble with — used by auto-assembly and as the reply page's default. Overrides the workspace default template. Pass null — or the current default's id — to clear the override so the collector follows the workspace default, tracking future default changes; the payload then reports template_id: null."},"auto_assemble_drafts":{"type":"boolean","description":"When true, every new finalized response automatically assembles a draft video using the collector's template (or the workspace default)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/add_prompt":{"post":{"operationId":"add_prompt","summary":"add prompt","description":"Add a new question (prompt) to the end of the collector's active prompts list. The new prompt is inserted before any inactive prompts so the questions respondents see stay in the user's intended order. Pass plain `text` for the question; optionally `teleprompter_script`, `max_recording_length`, `tips`, and `skippable`.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["collector_id","text"],"properties":{"collector_id":{"type":"integer"},"text":{"type":"string","description":"The question the respondent will see."},"teleprompter_script":{"type":"string","description":"Optional teleprompter copy shown to the responder."},"max_recording_length":{"type":"integer","description":"Optional cap on response length in seconds."},"tips":{"type":"string","description":"Optional tips shown next to the question."},"skippable":{"type":"boolean","description":"Optional. When true the respondent sees a \"Skip\" link and can pass on this question. Rejected on a collector's first question — that one is always required."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/update_prompt":{"post":{"operationId":"update_prompt","summary":"update prompt","description":"Edit an existing question (prompt) in place — its `text`, `teleprompter_script`, `max_recording_length`, `tips`, or `skippable`. Use to reword a question or adjust its settings WITHOUT removing it, so responses already recorded against the prompt are preserved (unlike remove + add). Find the prompt id via `get_collector`. Pass only the fields that change.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["collector_id","prompt_id"],"properties":{"collector_id":{"type":"integer"},"prompt_id":{"type":"integer","description":"Prompt id from get_collector."},"text":{"type":"string","description":"The question the respondent will see."},"teleprompter_script":{"type":"string","description":"Teleprompter copy shown to the responder."},"max_recording_length":{"type":"integer","description":"Cap on response length in seconds."},"tips":{"type":"string","description":"Tips shown next to the question."},"skippable":{"type":"boolean","description":"When true the respondent sees a \"Skip\" link and can pass on this question. Rejected on a collector's first question — that one is always required."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/remove_prompt":{"post":{"operationId":"remove_prompt","summary":"remove prompt","description":"Remove a prompt from a collector. Behaviour mirrors the in-app \"delete question\" verb: if the prompt has no recorded clips, it's destroyed outright; otherwise it's marked inactive (so existing clips stay intact). Refuses to remove the only active prompt from an active collector — set the collector inactive first, or add another prompt before removing.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["collector_id","prompt_id"],"properties":{"collector_id":{"type":"integer"},"prompt_id":{"type":"integer"}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/reorder_prompts":{"post":{"operationId":"reorder_prompts","summary":"reorder prompts","description":"Reorder a collector's active prompts. Pass the full ordered list of prompt ids — inactive prompts are pushed to the end automatically.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["collector_id","prompt_ids"],"properties":{"collector_id":{"type":"integer"},"prompt_ids":{"type":"array","items":{"type":"integer"},"description":"Full ordered list of active prompt ids."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_collector_status":{"post":{"operationId":"set_collector_status","summary":"set collector status","description":"Set a collector to `active` (accepting responses) or `inactive` (paused — link stops accepting submissions). Use for \"pause my hiring collector\", \"turn this back on\", etc.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["collector_id","status"],"properties":{"collector_id":{"type":"integer"},"status":{"type":"string","enum":["active","inactive"]}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/send_collector_invitation":{"post":{"operationId":"send_collector_invitation","summary":"send collector invitation","description":"Send a collector's video-request invitation to email addresses. Sends real email and spends one ask credit per recipient. TWO-STEP, token-gated. Call FIRST with `confirm: false` to get a preview (deliverable / skipped / invalid addresses) plus a `confirmation_token`. To send, call again with the SAME args, `confirm: true`, and `confirmation_token` set to that token. The token is short-lived and bound to the exact deliverable recipients; a bare `confirm: true` without a valid token will not send.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["collector_id","emails"],"properties":{"collector_id":{"type":"integer"},"emails":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses. Skipped reasons surface in the preview."},"message":{"type":"string","description":"Optional override for the invitation email body. Defaults to the collector's template copy."},"confirm":{"type":"boolean","description":"Set true only after the user has explicitly confirmed the preview. Defaults to false."},"confirmation_token":{"type":"string","description":"External API/MCP only: the token returned by the confirm:false preview. Required alongside confirm:true on that surface."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_storyboard_design":{"post":{"operationId":"set_storyboard_design","summary":"set storyboard design","description":"Update storyboard-wide design — theme, colors, fonts, soundtrack, watermark, thumbnail, caption settings. All fields optional; pass only what changes. Run `get_storyboard` first to see the current design summary if you need to read before writing. Use for \"make the brand color blue\", \"switch the theme to atlas\", \"turn off subtitles\", \"louder soundtrack\".\n\nFONT IDS — every *_font_id field takes a string, never a number: \"\u003cfamily\u003e_\u003cweight\u003e\" with optional \"_italics\" and/or \"_uppercase\" suffixes — e.g. \"outfit_bold\", \"playfair-display_regular_italics\". Weights: thin, light, regular, semibold, bold, heavy (single-weight display faces take the bare family id). Families: open-sans, roboto, outfit, inter, montserrat, comfortaa, lato, ubuntu, jura, source-code-pro, abril-fatface, gruppo, prompt, quicksand, arvo, raleway, orbitron, bungee, tomorrow, permanent-marker, barlow-condensed, source-serif-pro, noto-serif-tc, fraunces, oswald, roboto-slab, roboto-condensed, noto-sans, nunito, playfair-display, rubik, solway, lora, kanit, cinzel, pt-serif, dosis, libre-baskerville, bebas-neue, michroma, anton, lobster, fjalla-one, special-elite, audiowide, black-ops, monoton, creepster, caveat, fasthand, sacramento, dancing-script, azeret-mono, cairo, dm-sans, ibm-plex-mono, chakra-petch, space-grotesk, work-sans, spline-sans.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id"],"properties":{"apply_ai_effects_to_uploads":{"type":"boolean"},"aspect_ratio":{"type":"string","enum":["square","portrait","landscape"],"description":"Storyboard aspect ratio. \"landscape\" is widescreen/16:9, \"portrait\" is vertical/9:16, \"square\" is 1:1."},"attribution_name_font_id":{"type":"string","description":"Font id string, NOT a number — see FONT IDS in this tool's description."},"attribution_title_font_id":{"type":"string","description":"Font id string, NOT a number — see FONT IDS in this tool's description."},"audio_scene_accent_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"audio_scene_bg_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"audio_scene_card_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"audio_scene_text_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"color_a":{"type":"string","description":"Primary brand color, CSS hex."},"color_b":{"type":"string","description":"Secondary brand color, CSS hex."},"color_c":{"type":"string","description":"Tertiary brand color, CSS hex."},"color_d":{"type":"string","description":"Quaternary brand color, CSS hex."},"headline_font_id":{"type":"string","description":"Font id string, NOT a number — see FONT IDS in this tool's description."},"kicker_font_id":{"type":"string","description":"Font id string, NOT a number — see FONT IDS in this tool's description."},"logo_scene_accent_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"logo_scene_bg_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"logo_scene_card_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"logo_scene_text_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"show_subtitles":{"type":"boolean"},"show_watermark_logo":{"type":"boolean"},"song_id":{"type":["integer","null"],"description":"Stock-soundtrack song id; pass null to clear."},"soundtrack_volume":{"type":"number","description":"0.0–1.0 background music volume."},"studio_sound":{"type":"boolean"},"subhead_font_id":{"type":"string","description":"Font id string, NOT a number — see FONT IDS in this tool's description."},"subtitle_font_id":{"type":"string","description":"Font id string, NOT a number — see FONT IDS in this tool's description."},"subtitle_position":{"type":"integer","minimum":0,"maximum":100,"description":"Vertical caption position as a percentage: 100 = top of frame, 0 = bottom."},"text_scene_accent_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"text_scene_bg_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"text_scene_card_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"text_scene_text_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"theme_type":{"type":"string","enum":["Theme::Atlas","Theme::Callisto","Theme::Europa::Shaded","Theme::Europa::Flat","Theme::Janus","Theme::Titan","Theme::Sirius"],"description":"Theme class name, e.g. \"Theme::Atlas\"."},"thumbnail_accent_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"thumbnail_bg_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"thumbnail_filter":{"type":"string","enum":["grayscale","high_contrast_grayscale","sepia","sepia_strong","darken","darken_strong","lighten","lighten_strong","reduce_contrast","increase_contrast","increase_contrast_strong","saturate","saturate_strong","saturate_and_increase_contrast","desaturate","desaturate_strong","blur","blur_strong","shift_colors","invert_colors"]},"thumbnail_headline":{"type":"string","description":"Thumbnail headline text; empty string hides it.","maxLength":191},"thumbnail_kicker":{"type":"string","description":"Thumbnail kicker (small text above the headline); empty string hides it.","maxLength":191},"thumbnail_subhead":{"type":"string","description":"Thumbnail subhead (small text below the headline); empty string hides it.","maxLength":191},"thumbnail_text_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"thumbnail_text_style":{"type":"string","enum":["attribution","headline","none"],"description":"How the thumbnail text is laid out: \"headline\" as a title block, \"attribution\" as a name card, \"none\" hides it. Both visible styles show kicker, headline and subhead, so setting thumbnail text never needs a style change."},"video_bg_blur_amount":{"type":"integer"},"video_bg_effect":{"type":"string","enum":["off","blur","remove","replace"],"description":"\"off\" for none, \"blur\", \"remove\", or \"replace\"."},"video_frame":{"type":"string","enum":["zoom","fit"],"description":"\"zoom\" fills the frame (crops); \"fit\" letterboxes."},"video_scene_accent_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"video_scene_bg_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"video_scene_card_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"video_scene_text_color":{"type":"string","enum":["a","b","c","d","white","black"],"description":"Palette slot, not a hex value: \"a\"/\"b\"/\"c\"/\"d\" reference brand colors color_a–color_d, plus \"white\" and \"black\"."},"watermark_logo_position":{"type":"string","enum":["top_left","top_right"]},"caption_preset":{"type":"string","enum":["theme_default","hormozi","tiktok","studio_label","flashcard","comic_book","lift","sticker_pop","punch_in","skewed","zoom_in_bold","zoom_out_bold","karaoke_classic","karaoke_one_word","underline_sweep","pop","future_dim","zoom_in_clean","zoom_out_clean","glow","paper_trail","typewriter","console","brandline","editorial","executive","calm","quiet_focus","cctv","clean"],"description":"Apply a named caption preset (resets caption_* fields to that preset; any other caption_* fields you pass then override it). Use for \"use Hormozi-style captions\", or to match a customer's brand/tone and the video's purpose. Use the internal key, matching the displayed name or visual description below. Presets are grouped by register: pick the family the brief calls for, then the preset within it whose appearance and keywords best fit.\nOn-brand — follows the workspace theme\n  theme_default (Theme Default): Native theme typography and caption treatments; follows the selected theme. [default, on-brand, safe, professional, neutral, conservative]\nHigh energy — bold, punchy, kinetic; social, TikTok/Reels/Shorts, creator, ads\n  hormozi (Hormozi): Heavy uppercase white text, yellow active words, outlines and bouncing emphasis. [high-energy, hype, tiktok, reels, shorts, fitness, coaching, marketing, ads, creator]\n  tiktok (TikTok): Condensed bold uppercase white text, red word boxes and outlines. [tiktok, viral, high-energy, reels, shorts, creator, Pro font]\n  flashcard (Flashcard): One heavy uppercase black word at a time on a white card, zooming in. [high-energy, launch, hook, tiktok, reels, shorts, monochrome, one-word]\n  comic_book (Comic Book): Handwritten uppercase lettering with thick outlines; white upcoming words become lime, with comic phrase motion. [comic, playful, illustrated, hand-drawn, pop-art, Pro font]\n  sticker_pop (Sticker Pop): Rounded dark lettering on pink boxes, orange word highlights and a comic tilt/pop. [playful, creator, lifestyle, promo, pink, sticker, fun]\n  skewed (Skewed): Tilted heavy uppercase lettering with a blue sweeping underline and phrase fades. [skewed, tilted, sweeping, edgy, dynamic, urban, music, streetwear, gen-z]\n  zoom_in_bold (Bold Swell): One heavy outlined uppercase white word at a time, swelling into place. [cinematic, dramatic, swell, one-word]\n  zoom_out_bold (Bold Slide): One heavy outlined uppercase white word at a time, sliding up into place. [cinematic, dramatic, slide, rise, one-word]\n  pop (Pop): Rounded playful lettering with pink active-word boxes and bouncing emphasis. [playful, fun, lively, youthful, lifestyle, casual]\nBalanced — readable and versatile; explainer, educational, demo\n  studio_label (Bold): White Outfit on a vivid blue pill; phrase zooms in and upcoming words brighten. [confident, blue, prominent]\n  lift (Lift): Large white Outfit rises into view; mint active words gently pop, with a drop shadow. [upbeat, recruiting, saas, launch, customer-story, mint, modern]\n  punch_in (Punch In): White bold text on translucent rounded boxes with soft shadow and a zoom-through transition. [zoom, promo, announcement, modern]\n  karaoke_classic (Karaoke): Readable Montserrat on a pill background, with a blue fading active word. [karaoke, engaging, balanced, educational, general, versatile]\n  karaoke_one_word (Karaoke One Word): One bold word at a time with a blue highlight box. [focus, rhythmic, minimal-words, quotes, emphasis, one-word]\n  underline_sweep (Underline Sweep): Uppercase white Montserrat with a cyan underline that sweeps across the active word. [tutorial, demo, blue]\n  zoom_in_clean (Clean Swell): One rounded white word at a time, with a drop shadow, swelling into place. [clean, swell, one-word]\n  zoom_out_clean (Clean Slide): One rounded white word at a time, with a drop shadow, sliding up into place. [clean, slide, rise, one-word]\nRefined — elegant, premium, editorial; serif and atmospheric\n  future_dim (Ticker Tape): Black Playfair serif on white cards, pale-yellow word boxes and a phrase fade/zoom. [ticker-tape, news, editorial, serif, paper, cards, highlighted, premium, Pro font]\n  glow (Glow): Soft purple active-word glow and shadow, with dim upcoming words and slow fades. [elegant, atmospheric, premium, cinematic, beauty, luxury, wellness]\n  paper_trail (Paper Trail): Dark Lato on warm paper-colored boxes, with a yellow marker highlight. [coaching, advice, educational, paper, warm, marker]\n  editorial (Editorial): Large cream serif lettering with a fading active-word color and soft shadow. [editorial, refined, elegant, serif, founder, hospitality, storytelling, premium, Pro font]\nTechy — monospace, terminal and typewriter looks; developer and startup\n  typewriter (Typewriter): Left-aligned monospace text in a centered translucent strip; words appear one by one. Alignment is preset-specific, not an adjustable field. [typewriter, techy, retro, monospace, left-aligned, reveal, editorial, developer, indie, startup]\n  console (Console): Monospace over a frosted full-width band, with an orange sweeping underline. [console, terminal, code, monospace, technical, frosted]\nRestrained — professional, corporate, formal; testimonial and B2B\n  brandline (Brandline): White Inter with a simple active-word underline and soft shadow. [on-brand, case-study, product]\n  executive (Executive): Playfair serif on a translucent black strip; words reveal with a marker highlight. [professional, formal, customer-story, internal-communications, conservative, Pro font]\n  calm (Calm): Black Montserrat on pale-gray rounded boxes; dim words gently brighten without changing accent color. [calm, measured, testimonial, conversational]\n  quiet_focus (Quiet Focus): Bold Lato on a dark rounded box; upcoming words brighten slowly. [training, educational, guided, calm, focused]\n  cctv (CCTV): Light Inter on a translucent black strip; dim upcoming words, no phrase motion. [cctv, surveillance, security-camera]\n  clean (Clean): Plain white Inter, modest phrasing and a simple phrase fade; no box or highlight. [clean, professional, testimonial, formal, b2b]"},"caption_size":{"type":"integer","minimum":50,"maximum":200,"description":"Caption Size percentage: named presets use a shared 40px base at 1920×1080; Theme Default uses its theme base. Square/portrait apply a further 90% multiplier. 150 means 1.5× the base."},"caption_width":{"type":"integer","minimum":30,"maximum":100,"description":"Maximum caption box width within the caption area. Named presets use a centered area 70% of landscape canvas width, 80% of square/portrait. Narrower values increase wrapping."},"caption_max_words":{"type":"integer","minimum":1,"maximum":20,"description":"Max words shown at once; 1–3 gives Hormozi-style word-by-word captions."},"caption_lines":{"type":"integer","minimum":1,"maximum":3,"description":"Balance each phrase into this many lines, with at least two words per line when possible. Does not change phrase length; use caption_max_words for that. Narrow widths can wrap into additional lines."},"caption_pill_opacity":{"type":"integer","minimum":0,"maximum":100,"description":"Opacity of the phrase background box or frosted backdrop, from 0% transparent to 100% opaque."},"caption_highlight_style":{"type":"string","enum":["none","recolor","box","underline","pill","glow","marker","underline_sweep"],"description":"Active-word treatment. recolor uses the active-word color; marker draws a low stroke. underline_sweep needs a non-instant word animation (prefer fade) to sweep; instant makes it appear/disappear without sweeping."},"caption_background_style":{"type":"string","enum":["none","solid","rounded","pill"],"description":"Phrase background box: none, solid rectangle, rounded rectangle, or pill."},"caption_scrim":{"type":"string","enum":["none","gradient","frosted"],"description":"Full-width caption backdrop: none/gradient/frosted."},"caption_outline_style":{"type":"string","enum":["none","thin","thick","medium"],"description":"Letter outline thickness; uses the shared outline/shadow color."},"caption_shadow_style":{"type":"string","enum":["none","drop","soft"],"description":"Letter shadow: none, soft halo, or offset drop shadow; uses the outline/shadow color."},"caption_group_animation":{"type":"string","enum":["none","fade","fade_zoom","zoom_through","comic_pop","zoom_in","zoom_out","rise","swell"],"description":"Whole-phrase motion on entrance/exit, independent of active-word motion; rise slides upward, comic_pop tilts/pops, zoom_in/out move scale inward/outward, swell bumps the phrase up as it lands then holds still."},"caption_word_animation":{"type":"string","enum":["instant","fade","gentle_pop","bounce"],"description":"Active-word transition: instant switches immediately; fade smoothly changes highlight/opacity; gentle_pop adds a small scale pulse; bounce adds an elastic pulse. Use fade for a sweeping underline."},"caption_animation_speed":{"type":"string","enum":["slow","normal","fast"],"description":"Speed of phrase and word transitions. Slow lengthens transitions, clamped to the available word/phrase timing."},"caption_future_word_style":{"type":"string","enum":["none","dim","recolor","hidden"],"description":"Upcoming words: none shows normal text; dim starts at 40% opacity; recolor uses the independent upcoming-word color (default scene Accent); hidden reveals words when spoken. Spoken words return to Text; active-word styling applies independently."},"caption_rotation_angle":{"type":"integer","minimum":-10,"maximum":10,"description":"Caption Angle in degrees: negative tilts counterclockwise, positive clockwise."},"caption_text_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_highlight_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_future_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_pill_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_effect_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_text_color_hex":{"type":"string","description":"Custom caption text colour, CSS hex (overrides the caption_text_color slot)."},"caption_highlight_color_hex":{"type":"string","description":"Custom active-word colour, CSS hex."},"caption_future_color_hex":{"type":"string","description":"Custom upcoming-word colour, CSS hex. Used when caption_future_word_style is recolor; defaults to the scene accent."},"caption_pill_color_hex":{"type":"string","description":"Custom caption background colour, CSS hex."},"caption_effect_color_hex":{"type":"string","description":"Custom outline and shadow colour, CSS hex."},"storyboard_id":{"type":"integer","description":"Storyboard id."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/list_galleries":{"post":{"operationId":"list_galleries","summary":"list galleries","description":"Find galleries the user has built in their workspace. Returns a shortlist with layout style, view counts, slot count, and links. Use this for \"show me my galleries\", \"find my customer-highlights gallery\", or to decide which gallery to add a video to. Results carry `returned` (rows in this payload), `matched` (hits for the filters you sent — NOT a workspace total), and `truncated`. When `truncated` is true, narrow the filters rather than assuming you saw everything.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Full-text search across title, headline, and subhead."},"style":{"type":"string","enum":["carousel","slideshow","wall","grid","list"],"description":"Filter by layout style (`carousel`, `slideshow`, `wall`, `grid`, `list`)."},"visibility":{"type":"string","enum":["publicly","unlisted","privately"],"description":"`publicly` = public + searchable; `unlisted` = public link only; `privately` = workspace-only."},"starred":{"type":"boolean","description":"If true, return only starred (favorited) galleries."},"since_days":{"type":"integer","description":"Restrict to galleries created in the last N days."},"sort":{"type":"string","enum":["newest","oldest","view"],"description":"`newest` (default) by creation recency, `oldest` reverses it, `view` by total view count."},"limit":{"type":"integer","default":20,"maximum":50,"description":"Max results to return."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_gallery":{"post":{"operationId":"get_gallery","summary":"get gallery","description":"Fetch a single gallery by id. Returns the same payload as a `list_galleries` entry plus the design summary and the full items list (each slot's slot_id + type + typed slottable id + title, in display order). Use this before any add/remove/reorder or design change so you know what's currently in the gallery.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Gallery id from list_galleries."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/create_gallery":{"post":{"operationId":"create_gallery","summary":"create gallery","description":"Create a gallery, filled in the same call. When the user names what goes in it (\"a gallery of my best videos\"), pick the items yourself and pass them here — `storyboard_ids` for published videos, `clip_ids` for raw response clips, both in display order. Never create an empty gallery and ask the user which videos to add. Inherits brand defaults for colors and fonts. `style` picks the layout (default `grid`); carousel-style galleries get sensible auto-defaults for columns / card height. New galleries are PUBLIC. Calling this makes the new gallery the conversation's subject, which is what puts the tools that reorder, restyle and hide it in reach — those arrive with the user's next message, not this one.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Internal gallery title (workspace-only).","maxLength":191},"headline":{"type":"string","description":"Public-facing headline shown above the items.","maxLength":191},"subhead":{"type":"string","description":"Public-facing subhead under the headline."},"style":{"type":"string","enum":["carousel","slideshow","wall","grid","list"],"description":"Layout: `grid` (default), `carousel`, `slideshow`, `wall`, `list`."},"storyboard_ids":{"type":"array","items":{"type":"integer"},"description":"Published videos to fill the gallery with, in display order. Drafts are rejected — publish first or leave them out."},"clip_ids":{"type":"array","items":{"type":"integer"},"description":"Raw response clips to fill the gallery with, in display order. Added after any `storyboard_ids`."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_gallery_share_url":{"post":{"operationId":"get_gallery_share_url","summary":"get gallery share url","description":"Return the public share URL for a gallery. Surfaces a warning when the gallery is set to `privately` (only workspace members can open the link).","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id"],"properties":{"gallery_id":{"type":"integer"}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_gallery_embed_code":{"post":{"operationId":"get_gallery_embed_code","summary":"get gallery embed code","description":"Return the HTML embed code for a gallery. Gallery embeds do not accept per-call options — the look is driven by the gallery's persisted design (style, columns, colors). Use `set_gallery_design` to change those before getting embed code if needed.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id"],"properties":{"gallery_id":{"type":"integer"}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/add_storyboard_to_gallery":{"post":{"operationId":"add_storyboard_to_gallery","summary":"add storyboard to gallery","description":"Add published videos to a gallery as new items at the end. Adding several is ONE call: pass every id in `storyboard_ids`, in display order — never a call per video. Idempotent — a video already in the gallery comes back as its existing slot with `already_present: true`. Drafts cannot be added.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id"],"properties":{"gallery_id":{"type":"integer"},"storyboard_id":{"type":"integer","description":"A single published video."},"storyboard_ids":{"type":"array","items":{"type":"integer"},"description":"Several published videos at once, added in array order. Preferred whenever there is more than one."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/add_clip_to_gallery":{"post":{"operationId":"add_clip_to_gallery","summary":"add clip to gallery","description":"Add individual clips (a single recorded segment, not a video cut) to a gallery as new items at the end. Same shape as `add_storyboard_to_gallery`, plural form included: several clips is ONE call passing `clip_ids`.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id"],"properties":{"gallery_id":{"type":"integer"},"clip_id":{"type":"integer","description":"A single clip."},"clip_ids":{"type":"array","items":{"type":"integer"},"description":"Several clips at once, added in array order. Preferred whenever there is more than one."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/remove_from_gallery":{"post":{"operationId":"remove_from_gallery","summary":"remove from gallery","description":"Remove one item from a gallery. Pass `slot_id` (preferred — unique per gallery), or `storyboard_id` / `clip_id` to remove by the underlying item. Does not delete the video or clip itself, only the gallery slot.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id"],"properties":{"gallery_id":{"type":"integer"},"slot_id":{"type":"integer","description":"Slot id from get_gallery.items[].slot_id. Preferred."},"storyboard_id":{"type":"integer","description":"Storyboard id — used to look up the slot if slot_id isn't passed."},"clip_id":{"type":"integer","description":"Clip id — used to look up the slot if slot_id isn't passed."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/reorder_gallery":{"post":{"operationId":"reorder_gallery","summary":"reorder gallery","description":"Reorder gallery items by passing the full `slot_ids` array in the desired display order. Slot ids come from `get_gallery`.items[].slot_id — do NOT use the typed storyboard_id / clip_id fields here.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id","slot_ids"],"properties":{"gallery_id":{"type":"integer"},"slot_ids":{"type":"array","items":{"type":"integer"},"description":"Full ordered list of slot ids."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/rotate_gallery":{"post":{"operationId":"rotate_gallery","summary":"rotate gallery","description":"Curate a gallery in one call by removing stale videos and backfilling with the most-recently-published videos not already in it. Use for \"rotate this gallery to my newest videos\" or \"keep this gallery fresh\". Only operates on storyboard slots — clip slots are never removed. `replace_older_than_days` controls which videos qualify; optional `keep_top_n` protects that many leading storyboard slots regardless of age.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id","replace_older_than_days"],"properties":{"gallery_id":{"type":"integer"},"replace_older_than_days":{"type":"integer","minimum":1,"description":"Remove storyboard slots whose video was published more than N positive days ago. Drafts and never-published storyboards always qualify."},"keep_top_n":{"type":"integer","description":"Protect the first N storyboard slots from removal, regardless of age. Useful for keeping a pinned hero at the top."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_gallery_design":{"post":{"operationId":"set_gallery_design","summary":"set gallery design","description":"Update one or more design fields on a gallery (layout style, columns, card type, colors, fonts, shadows, corner radius). All fields optional; pass only what changes. For the full set of current values, call `get_gallery` first.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id"],"properties":{"gallery_id":{"type":"integer"},"style":{"type":"string","enum":["carousel","slideshow","wall","grid","list"]},"column_count":{"type":"integer","minimum":2,"maximum":5},"card_type":{"type":"string","enum":["video_only","standard","transparent","video_left","video_inset_left","video_left_transparent","centered"]},"card_height":{"type":"string","enum":["auto","small","medium","large"]},"background":{"type":"string","description":"Background CSS color."},"corner_radius":{"type":"string","enum":["square","small","large"]},"shadows":{"type":"string","enum":["none","small","large"]},"heading_color":{"type":"string"},"body_color":{"type":"string"},"item_accent_color":{"type":"string"},"item_heading_color":{"type":"string"},"item_body_color":{"type":"string"},"item_background_color":{"type":"string"},"heading_font_id":{"type":"integer"},"text_font_id":{"type":"integer"}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_gallery_metadata":{"post":{"operationId":"set_gallery_metadata","summary":"set gallery metadata","description":"Update a gallery's content text — title, headline, and/or subhead. Separate from set_gallery_design (layout / colors / fonts) and set_gallery_visibility. Use for \"rename my gallery\", \"change the gallery headline / subhead\". Pass only the fields that change.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id"],"properties":{"gallery_id":{"type":"integer"},"title":{"type":"string","description":"Gallery title.","maxLength":191},"headline":{"type":"string","description":"Headline shown above the gallery items.","maxLength":191},"subhead":{"type":"string","description":"Subhead shown below the headline."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_gallery_visibility":{"post":{"operationId":"set_gallery_visibility","summary":"set gallery visibility","description":"Change a gallery's visibility. `publicly` = public + indexed by search engines; `unlisted` = anyone with the link can view; `privately` = only workspace members can view.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gallery_id","visibility"],"properties":{"gallery_id":{"type":"integer"},"visibility":{"type":"string","enum":["publicly","unlisted","privately"]}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/list_replies":{"post":{"operationId":"list_replies","summary":"list replies","description":"Find footage (video/audio responses) matching the user's intent. The PRIMARY filter tool — combine parameters to narrow to a usable shortlist in one call. Use `query` for keyword search across transcripts and respondent metadata; use the structured filters (response_type, sentiment, specificity, topics, firmographics) for everything else. Returns metadata + a one-line summary per reply. Do NOT call `get_reply` to filter — that's only for committing a reply to a scene. If the result is `{replies: [], index_status: \"pending\"}`, the workspace HAS responses but they're still being indexed — tell the user their responses are still being prepared and to try again shortly; do NOT say the workspace is empty or has no footage, and do NOT build an empty storyboard. Results carry `returned` (rows in this payload), `matched` (hits for the filters you sent — NOT a workspace total), and `truncated`. When `truncated` is true, narrow the filters rather than assuming you saw everything.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Full-text search across transcript content, respondent name, job title, and company. Pass when the user's request implies a topic, theme, or keyword (e.g., 'hiring', 'onboarding', 'team culture'). Omit for unfiltered browse by recency."},"response_type":{"type":"string","enum":["testimonial","personal_message","leadership_message","expert_content","hiring_screening","impact_story","other"],"description":"Filter by response shape. `testimonial` is the default for customer/employee endorsements (~60% of corpus). `personal_message` is greetings/dedications addressed to specific people. `leadership_message` is exec/leadership outbound to a group. `expert_content` is educational/tutorial from an expert. `hiring_screening` is job/scholarship applications — exclude from marketing storyboards. `impact_story` is beneficiary/program narrative. For most storyboard-building, default to `testimonial` or omit to scan everything."},"sentiment":{"type":"string","enum":["positive","negative","neutral","mixed"],"description":"Filter by inferred sentiment. Useful for 'positive customer testimonials' or 'critical product feedback'. Corpus skews positive — `negative` / `mixed` filters meaningfully narrow."},"specificity":{"type":"string","enum":["low","medium","high"],"description":"Filter by how concrete the response is. `high` = specific outcomes, numbers, named details ('cut deployment time in half'). `low` = generic praise ('game changer', 'top-notch'). Storyboards usually benefit from `medium` or `high`. Pass `high` when the user wants impact-driven content."},"topics":{"type":"array","items":{"type":"string"},"description":"Filter to replies whose extracted topics overlap with these terms (any-match, case-insensitive). Example: ['team culture', 'onboarding']."},"job_title_contains":{"type":"string","description":"Substring match on respondent job_title (case-insensitive)."},"company_contains":{"type":"string","description":"Substring match on respondent company_name (case-insensitive)."},"collector_id":{"type":"integer","description":"Restrict to one specific collector (a particular ask or survey)."},"format":{"type":"string","enum":["video","audio"]},"starred":{"type":"boolean","description":"If true, return only starred (favorited) responses."},"has_release":{"type":"boolean","description":"If true, return only responses with a signed release — safe for public use."},"since_days":{"type":"integer","description":"Optional narrowing window — restrict to responses from the last N days. Results are already returned in recency order by default; only pass this when the user has expressed an explicit time constraint (e.g. \"from this quarter\", \"last month\"). Do NOT pass it for vague phrasings like \"recent\" — the natural sort handles that."},"limit":{"type":"integer","default":20,"maximum":50,"description":"Max results to return."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_reply":{"post":{"operationId":"get_reply","summary":"get reply","description":"Fetch the full reply payload for one reply. Returns the respondent metadata, the LLM analysis (summary, sentiment, topics, pull_quote), and a `clips` array — each clip carries its `sentences` with per-sentence `{text, start, finish, gap_after}` timecodes you can use to pick sub-moments for `add_scene` `segments` (`gap_after` is the silence before the next sentence — prefer out-points with a real pause). `pull_quote` is present only when its transcript locates it as one contiguous run; `pull_quote_moment` then carries `{clip_id, start, finish, confidence}` — the ready-to-use hook moment. Call this once you've decided to commit a reply to a scene; the `summary` and `topics` from `list_replies` are enough to shortlist.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Reply id from list_replies."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_replies":{"post":{"operationId":"get_replies","summary":"get replies","description":"Batch read of full payloads for multiple replies in one turn. Pass an `ids` array — up to 6 ids are served, extras come back in `omitted_ids` for a follow-up call. Use this for multi-respondent storyboard builds instead of looping `get_reply`. Returns `{ replies, not_found_ids?, omitted_ids? }`; each reply has the same shape as `get_reply` (sentences, pull_quote_moment, etc.).","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","description":"Reply ids from list_replies. Duplicates collapsed.","items":{"type":"integer"}}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/star_reply":{"post":{"operationId":"star_reply","summary":"star reply","description":"Mark a response as starred (the user's favorites). Idempotent — calling on an already-starred response is a no-op. Use this when the user says \"favorite this\", \"star Zach's response\", or as cleanup after picking the strongest entries from a `list_replies` result.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Reply id from list_replies."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/unstar_reply":{"post":{"operationId":"unstar_reply","summary":"unstar reply","description":"Remove the starred flag from a response. Idempotent — calling on a response that isn't starred is a no-op. Use this for \"unstar this\", \"remove the favorite\", or to clean up after a bad star.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Reply id from list_replies."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_scene":{"post":{"operationId":"get_scene","summary":"get scene","description":"Read a single scene's current content — transcript (post-trim, post-mute), segments with their effects, mute segments, text fields, duration, and style. Use before mutating a scene's content (set_scene_duration, set_scene_segments, mute_words) so you know what's there. For a bird's-eye view of every scene, use `get_storyboard` instead — calling `get_scene` per scene to build a list is wasteful.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Scene id, as returned in get_storyboard's `scenes[].id`."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/delete_scene":{"post":{"operationId":"delete_scene","summary":"delete scene","description":"Soft-delete a scene from a storyboard. The delete is reversible — call `restore_scene` with the same scene id to bring it back. Use when removing, dropping, cutting, or skipping a specific scene.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Scene id from get_storyboard."},"storyboard_id":{"type":"integer","description":"Optional. When set, the scene must belong to this storyboard — scopes the edit (recommended for API/MCP callers)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/restore_scene":{"post":{"operationId":"restore_scene","summary":"restore scene","description":"Restore a previously-deleted scene. Rarely needed — the user usually undoes deletes via Cmd+Z. Use when the user explicitly asks to bring back a scene they previously asked to remove.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Scene id to restore."},"storyboard_id":{"type":"integer","description":"Optional. When set, the scene must belong to this storyboard — scopes the edit (recommended for API/MCP callers)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/reorder_scenes":{"post":{"operationId":"reorder_scenes","summary":"reorder scenes","description":"Reorder the scenes of a storyboard. Pass every active scene id in the new order; partial reorders aren't supported. Use for \"move scene 3 before scene 1\", \"put the logo at the end\", or whole-reel restructuring.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id","scene_ids"],"properties":{"storyboard_id":{"type":"integer"},"scene_ids":{"type":"array","items":{"type":"integer"},"description":"All active scene ids in the desired order. Must cover every active scene exactly once."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_scene_duration":{"post":{"operationId":"set_scene_duration","summary":"set scene duration","description":"Set how long a text or logo scene stays on screen. Range is 1–30 seconds (out-of-range values are clamped). Use for \"make the intro card longer\" or duration-target arithmetic. Does NOT apply to video or audio scenes — their duration comes from the underlying clip and segments. Use `set_scene_segments` to trim a media scene.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","seconds"],"properties":{"id":{"type":"integer","description":"Text or logo scene id."},"seconds":{"type":"number","description":"Duration in seconds. Clamped to 1–30."},"storyboard_id":{"type":"integer","description":"Optional. When set, the scene must belong to this storyboard — scopes the edit (recommended for API/MCP callers)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_scene_segments":{"post":{"operationId":"set_scene_segments","summary":"set scene segments","description":"Replace the playback segments on a video or audio scene — the in/out cuts and per-segment zoom effects. Mirrors `add_scene`'s `segments:` shape but applies to an existing scene; the old segment list is replaced entirely. Use for \"trim that scene to just the part where she says…\", \"remove the filler in the middle of scene 3\", or after `get_scene` reveals a clip you want to retrim. Each segment carries `{start, finish}` in clip-local seconds with optional `effect`, `amount`, `focus`. Returns `storyboard_total_seconds` — the whole video's new length — so when cutting toward a target runtime, read it after each trim rather than tracking a running total yourself. When cutting inside a clip, also pass `opening_words` / `closing_words` — the cut word-aligns to the quoted transcript words, with `start`/`finish` locating which occurrence and standing in if the quote does not match.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","segments"],"properties":{"id":{"type":"integer","description":"Video or audio scene id."},"storyboard_id":{"type":"integer","description":"Optional. When set, the scene must belong to this storyboard — scopes the edit (recommended for API/MCP callers)."},"segments":{"type":"array","description":"Replacement segments in playback order. Each `{start, finish}` is clip-local seconds; finish must exceed start.","items":{"type":"object","required":["start","finish"],"properties":{"start":{"type":"number"},"finish":{"type":"number"},"opening_words":{"type":"string","description":"First few words of the span, verbatim from the transcript; the cut start aligns to them."},"closing_words":{"type":"string","description":"Last few words of the span, verbatim from the transcript; the cut finish aligns to them."},"effect":{"type":"string","enum":["punch","quick_zoom","zoom_in","slow_zoom","slow_zoom_out"]},"amount":{"type":"string","enum":["low","medium","high"]},"focus":{"type":"string","enum":["center","top_center"]}}}}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_scene_text":{"post":{"operationId":"set_scene_text","summary":"set scene text","description":"Update the overlay text on an existing scene. Pass at least one of headline, subhead, or kicker. Use for renaming overlays, tightening copy, or swapping a generic headline for a line drawn from what this scene's clip actually says. On a video or audio scene the headline and subhead are the respondent's name and title, shared by every scene that uses the same response, so one call updates them all.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer"},"headline":{"type":"string","maxLength":191},"subhead":{"type":"string","maxLength":191},"kicker":{"type":"string","maxLength":191},"storyboard_id":{"type":"integer","description":"Optional. When set, the scene must belong to this storyboard — scopes the edit (recommended for API/MCP callers)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/share_draft_for_review":{"post":{"operationId":"share_draft_for_review","summary":"share draft for review","description":"Email a draft video to workspace teammates for review. TWO-STEP, token-gated. Call FIRST with `confirm: false` to get a preview plus a `confirmation_token`. To send, call again with the SAME args, `confirm: true`, and `confirmation_token` set to that token. The token is short-lived and bound to the exact recipients — change the recipients and you must re-preview. A bare `confirm: true` without a valid token will not send. Only existing workspace members can be emailed (unknown addresses are reported, never invited). Drafts only.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id","emails"],"properties":{"storyboard_id":{"type":"integer"},"emails":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses. Invalid addresses are reported back in the preview."},"message":{"type":"string","description":"Optional note from the user, included in each share email."},"confirm":{"type":"boolean","description":"Set to true only after the user has explicitly confirmed the preview. Defaults to false (preview only)."},"confirmation_token":{"type":"string","description":"External API/MCP only: the token returned by the confirm:false preview. Required alongside confirm:true on that surface."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/add_scene":{"post":{"operationId":"add_scene","summary":"add scene","description":"Add one or more scenes to a storyboard. To BUILD or extend a video, pass the whole list at once in `scenes` (an array of scene objects) — a complete build is a SINGLE add_scene call, never one call per scene. To insert just one scene, pass that scene's fields at the top level instead. Each scene has three media-source modes: (1) reply-scoped — pass `reply_id` and optionally `clip_id` to use a specific clip from that reply; (2) workspace upload — pass `clip_id` ALONE (no reply_id) for a standalone workspace-uploaded clip like an animated logo, branded intro/outro, or stats overlay (find these via list_uploaded_clips); (3) structural — `template: \"text\"` + `headline` for a text card, `template: \"logo\"` (no clip) for a bare logo card. For reply-scoped media scenes, `segments` carries sentence-level internal cuts, each optionally carrying an `effect` to mask a trim or emphasize a moment. Positions are 1-indexed and optional — scenes append in array order when omitted.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id"],"properties":{"storyboard_id":{"type":"integer","description":"The storyboard to add scenes to."},"energy":{"type":"string","enum":["natural","punchy"],"description":"The cut's energy register — derive it from the template direction on assembly builds, from the user's ask otherwise. `punchy` renders emphasis markers as punch-ins; `natural` stores them unstyled."},"scenes":{"type":"array","description":"Preferred for building or extending a video: every scene in ONE call. Each item is a scene object with the same fields — and the same meanings — as a single scene (below); read the field descriptions there. Scenes are added in array order; omit per-scene `position` to append in order.","items":{"type":"object","properties":{"position":{"type":"integer"},"template":{"type":"string","enum":["audio","logo","text","video"]},"reply_id":{"type":"integer"},"clip_id":{"type":"integer"},"headline":{"type":"string","maxLength":191},"subhead":{"type":"string","maxLength":191},"kicker":{"type":"string","maxLength":191},"segments":{"type":"array","items":{"type":"object","required":["start","finish"],"properties":{"start":{"type":"number"},"finish":{"type":"number"},"opening_words":{"type":"string"},"closing_words":{"type":"string"},"emphasize_words":{"type":"string"},"effect":{"type":"string","enum":["punch","quick_zoom","zoom_in","slow_zoom","slow_zoom_out"]},"amount":{"type":"string","enum":["low","medium","high"]},"focus":{"type":"string","enum":["center","top_center"]}}}},"duration_seconds":{"type":"number"}}}},"position":{"type":"integer","description":"1-indexed position. Optional — omit to append (scene count + 1, or array order within `scenes`)."},"template":{"type":"string","enum":["audio","logo","text","video"],"description":"Scene type. Defaults to the clip's format when reply_id or clip_id is set. `\"logo\"` creates a structural card (e.g. outro for a highlight reel) and ignores reply_id / clip_id."},"reply_id":{"type":"integer","description":"For reply-scoped video/audio scenes, the reply whose clip will be used. Omit when pairing clip_id with a workspace upload, or for text and logo scenes."},"clip_id":{"type":"integer","description":"A specific clip id. With reply_id: a clip from that reply (defaults to the reply's pull-quote or first clip when omitted). Without reply_id: a workspace standalone upload (animated logo, branded intro/outro, stats overlay). Find workspace uploads with list_uploaded_clips."},"headline":{"type":"string","description":"Overlay headline. Defaults to the responder's name for video/audio scenes. Required for text scenes. Optional for logo scenes — omit for a bare outro.","maxLength":191},"subhead":{"type":"string","description":"Optional second line. Defaults to job_title for video/audio scenes.","maxLength":191},"kicker":{"type":"string","description":"Optional kicker text above the headline.","maxLength":191},"segments":{"type":"array","description":"Optional internal in/out cuts for a video/audio clip. Each entry is `{start, finish}` in seconds (relative to the clip), with an optional per-segment `effect` (with `amount` / `focus`) to mask a trim or emphasize a moment. Use to trim filler at sentence boundaries, pull a specific moment (like a `pull_quote_moment`), or stitch multiple sub-moments from one clip. Trim boundaries are snapped outward into natural whitespace (up to 0.3s) so cuts land between words. When cutting inside a clip, also pass `opening_words` / `closing_words` — the cut word-aligns to the quoted transcript words, with `start`/`finish` locating which occurrence and standing in if the quote does not match. Assembly builds only: an unanchored mid-sentence finish retracts to the last sentence end, and a segment after an excision gets a masking quick_zoom — interactive cuts play exactly as given. `emphasize_words` markers are treated on every path per the `energy` register. Omit to play the full clip.","items":{"type":"object","required":["start","finish"],"properties":{"start":{"type":"number","description":"Start time in seconds (0 = beginning of clip)."},"finish":{"type":"number","description":"Finish time in seconds. Must be greater than start."},"opening_words":{"type":"string","description":"The first few words of the span, verbatim from the transcript. The cut start aligns to these words."},"closing_words":{"type":"string","description":"The last few words of the span, verbatim from the transcript. The cut finish aligns to these words."},"emphasize_words":{"type":"string","description":"Optional: a short phrase inside this span, verbatim from the transcript, that deserves emphasis — the moment a good editor would accent. This marks the moment; whether and how it is styled is decided elsewhere."},"effect":{"type":"string","enum":["punch","quick_zoom","zoom_in","slow_zoom","slow_zoom_out"],"description":"Optional zoom effect applied to THIS segment. `punch` — immediate static scale, no animation. Good for a hard accent on a key word. `quick_zoom` — 0.2s push-in then release. Good for covering an internal trim. `zoom_in` — 1s push-in then release. Good for emphasis on a punchline. `slow_zoom` — gentle drift across the whole segment. The hook treatment. `slow_zoom_out` — reverse drift. Alternative hook treatment."},"amount":{"type":"string","enum":["low","medium","high"],"description":"Zoom strength. low = 1.1×, medium = 1.25×, high = 1.5×. Defaults to medium."},"focus":{"type":"string","enum":["center","top_center"],"description":"Focal point. `center` (default) or `top_center` when faces sit high in frame."}}}},"duration_seconds":{"type":"number","description":"For text scenes: how many seconds the card stays on screen. Defaults to 5s. For logo scenes: defaults to 6s. Ignored on video/audio scenes (duration comes from the clip / segments)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/assemble_draft":{"post":{"operationId":"assemble_draft","summary":"assemble draft","description":"Assemble a complete draft video from one response using a workspace template — the same pipeline as the reply page's \"New draft video\" action. THE standard tool for \"build/make me a video from X's response\": the template supplies the structure and design, and the assembly pipeline picks scenes, trims, and intro/outro server-side. Prefer this over create_storyboard + add_scene, which remains the path for multi-respondent reels and bespoke cuts. When `template_id` is omitted the template resolves automatically — the reply's collector template, else the workspace default — and the result reports the resolved `template_id` / `template_name` so you can tell the user which was used. Returns immediately with `assembly: \"building\"` while the cut is assembled in the background; until `assembly` is \"complete\" the draft is not editable — do not add scenes to it. Share the `editor_url` (it shows build progress, then opens the finished draft), or check later with `get_storyboard_summary`. Does not change the conversation's open video.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reply_id"],"properties":{"reply_id":{"type":"integer","description":"Reply id (from list_replies) to assemble the draft from."},"template_id":{"type":"integer","description":"Optional. Workspace template id (from list_templates) to assemble with, overriding the reply's collector template and the workspace default. Only pass when the user names a template."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/create_storyboard":{"post":{"operationId":"create_storyboard","summary":"create storyboard","description":"Create a new draft storyboard in the user's current workspace. When the user names a workspace template (\"our Customer Spotlights template\") call list_templates first and pass its id as `template_id` — the new storyboard inherits the template's visual settings (aspect ratio, theme, colors, captions, soundtrack, polish flags) and its editorial direction. Otherwise the storyboard inherits workspace defaults. Explicit polish flags (filler_word_removal, shorten_word_gaps, studio_sound) override the inherited settings either way. After creating, use `add_scene` to populate it with content. The result carries `template_guidance` — the template's structure, direction and duration costs; read it before `add_scene`. Calling this binds the conversation to the new storyboard — subsequent turns are storyboard-scoped — and a second call in the same turn is refused: fix a cut with the scene tools next turn, never by building again.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"Public-facing title — shown on the share page, embed, and social shares (like a YouTube video title). For a highlight reel: a punchy quote-derived line. For a full-length cut: plainly descriptive. Keep under ~80 characters.","maxLength":191},"internal_title":{"type":"string","description":"Optional. Workspace-only disambiguation label, never shown publicly. Use the respondent name + cut length/kind (\"Matt Scott - 30 second highlight\") when the public title is short or might collide with other reels. Skip when the public title is already unique."},"description":{"type":"string","description":"Optional. Public-facing description, shown below the title on the share / embed page (like a YouTube description). One or two sentences, under ~200 characters. Set for highlight reels and themed multi-respondent reels; usually skip for single-respondent full cuts where the title says enough."},"filler_word_removal":{"type":"boolean","description":"Mute filler words (\"um\", \"uh\") in every scene. Omit to inherit the template/workspace setting; set true for a punchy, polished cut."},"shorten_word_gaps":{"type":"boolean","description":"Tighten pacing by trimming long silences between words in every scene. Omit to inherit the template/workspace setting; set true for a fast-paced cut."},"studio_sound":{"type":"boolean","description":"Enhance voice audio at render. Omit to inherit the template/workspace setting."},"template_id":{"type":"integer","description":"Optional. Workspace template id (from list_templates). When set, the new storyboard inherits the template's full settings (aspect ratio, theme, colors, captions, soundtrack, polish flags) and its editorial direction. Prefer this whenever the user names a workspace template (\"our YouTube Flow template\", \"the Instagram Reel template\") or already has a default template configured."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/list_storyboards":{"post":{"operationId":"list_storyboards","summary":"list storyboards","description":"Find videos (storyboards) the user has already created. The PRIMARY discovery tool for videos — composes filters and full-text search and returns a shortlist with metadata + view/play counts in one call. Use this for asks like \"show me my recent videos\", \"find my testimonial videos about onboarding\", \"my most-viewed videos\", or to pick videos to add to a gallery. Each result carries `classification` aggregated from the source responses (topics / sentiment / response_type / specificity) so you can filter or narrate without a follow-up read. Results carry `returned` (rows in this payload), `matched` (hits for the filters you sent — NOT a workspace total), and `truncated`. When `truncated` is true, narrow the filters rather than assuming you saw everything.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Full-text search across title, internal title, description, and the full transcript. Pass when the user names a topic, theme, or keyword. Omit for unfiltered browse by recency."},"status":{"type":"string","enum":["draft","published"],"description":"Filter by lifecycle. `published` covers anything the user has shipped (including publishing-in-progress / errored renders); `draft` covers unfinished editor work. Omit for both. Archived videos are never returned."},"visibility":{"type":"string","enum":["publicly","unlisted","privately"],"description":"Filter by public visibility. `publicly` = public + searchable; `unlisted` = public link only; `privately` = workspace-only. Useful for \"show me public videos\" or \"find my private drafts\"."},"aspect_ratio":{"type":"string","enum":["square","portrait","landscape"],"description":"Filter by aspect ratio: `landscape`, `portrait`, or `square`."},"starred":{"type":"boolean","description":"If true, return only starred videos (the user's favorites)."},"since_days":{"type":"integer","description":"Restrict to videos created in the last N days (based on draft creation date). Only pass when the user named an explicit time window (\"this quarter\", \"last month\"). For \"videos I published this quarter\" use `since_published_days` instead. Results are recency-ordered by default — don't pass this for vague \"recent\"."},"since_published_days":{"type":"integer","description":"Restrict to videos published in the last N days (based on last_published_at). Use this for \"newly published\", \"shipped this quarter\", or gallery-refresh asks (\"rotate in my newest published videos\"). Drafts have no publish date and will not match."},"sort":{"type":"string","enum":["newest","oldest","play","view","published"],"description":"`newest` (default) by creation recency, `oldest` reverses it, `play` orders by total play count, `view` by total view count, `published` orders by last publish date (drafts sort last). Pick `play` or `view` for \"most popular\" / \"best performing\" asks; pick `published` for \"most recently shipped\"."},"limit":{"type":"integer","default":20,"maximum":50,"description":"Max results to return."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_storyboard_summary":{"post":{"operationId":"get_storyboard_summary","summary":"get storyboard summary","description":"Light read of a single video by id, usable from any context. Returns the same payload as one entry from `list_storyboards` plus the design summary and scene count — no scene transcripts, no per-shot data. Use this when the user references a specific video by name or url and you need its current metadata before acting (e.g., adding it to a gallery, changing its visibility, or sharing it). For active editor work use `get_storyboard` instead — that surface returns the full scene list and polish flags.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Storyboard id from list_storyboards."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_storyboard":{"post":{"operationId":"get_storyboard","summary":"get storyboard","description":"Read the current state of a storyboard (the \"video\" the user is editing). Returns scene-by-scene metadata, design summary (theme, fonts, colors), polish flags (filler-word removal, gap shortening, word-gap threshold, studio sound), scene count, and total duration. Use before any multi-step refinement so you know what's actually in the video — duration math for \"make it 60 seconds\", which scenes to delete for \"focus on team culture\", what theme is in play before tweaking design. Cheap: one query, no transcripts.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Storyboard id (e.g., from list_storyboards)."},"summary":{"type":"boolean","description":"If true, return the lighter get_storyboard_summary payload (no scene list, no polish flags). Useful when picking a video from a list and you only need its metadata + design summary."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_storyboard_metadata":{"post":{"operationId":"set_storyboard_metadata","summary":"set storyboard metadata","description":"Update top-level storyboard metadata — public title, internal title, or public description. All fields optional; pass only what changes. The natural \"rename it\" tool. URL slug edits are not supported here; direct the user to the in-editor edit modal if they ask to change a video's URL.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id"],"properties":{"storyboard_id":{"type":"integer"},"title":{"type":"string","description":"Public-facing title (share page, embed). Keep under ~80 characters.","maxLength":191},"internal_title":{"type":"string","description":"Workspace-only disambiguation label. Never shown publicly."},"description":{"type":"string","description":"Public-facing description (share / embed). Under ~200 characters."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_storyboard_visibility":{"post":{"operationId":"set_storyboard_visibility","summary":"set storyboard visibility","description":"Change a video's visibility. `publicly` = public + indexed by search engines; `unlisted` = anyone with the link can view; `privately` = only workspace members can view. Use this when the user says \"make this video public\", \"unlist this one\", \"lock this down to my team\". Does not affect drafts (drafts have no public page regardless of visibility).","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id","visibility"],"properties":{"storyboard_id":{"type":"integer"},"visibility":{"type":"string","enum":["publicly","unlisted","privately"],"description":"`publicly` (public + searchable), `unlisted` (public link only), or `privately` (workspace-only)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_storyboard_share_url":{"post":{"operationId":"get_storyboard_share_url","summary":"get storyboard share url","description":"Return the public share URL for a published video. Use this for \"what's the link to my testimonials reel?\", \"give me the URL for sharing this video\", or before composing copy that needs the share link. If the video is set to `privately`, the response carries a warning the agent should surface to the user — the URL exists but only workspace members can open it. Drafts have no public page and return an error.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id"],"properties":{"storyboard_id":{"type":"integer"}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/get_storyboard_embed_code":{"post":{"operationId":"get_storyboard_embed_code","summary":"get storyboard embed code","description":"Return the HTML embed code for a published video plus the resolved options. Use this for \"give me the embed code for the testimonials reel\", \"I want the embed with autoplay off\", or any \"how do I put this on my site\" ask. Embed options are passed per-call (the underlying form object is not persisted). Defaults fire when an option is omitted — most users only override `autoplay`, `max_width`, or `popover`. Drafts have no embed code and return an error.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id"],"properties":{"storyboard_id":{"type":"integer"},"alignment":{"type":"string","enum":["Left","Center"],"description":"`Center` (default) or `Left`. Applies when the embed is narrower than its container."},"autoplay":{"type":"boolean","description":"If true, the video starts muted on page load."},"corners":{"type":"string","enum":["square","small","large"],"description":"`square` (default), `small`, or `large` corner radius."},"max_width":{"type":"integer","enum":[360,540,720,1080,1920],"description":"Cap the embed width in pixels. Omit to use the storyboard's aspect-ratio-derived default."},"popover":{"type":"boolean","description":"If true, the embed renders as a clickable thumbnail that opens the video in a popover."},"shadow":{"type":"string","enum":["None","Thin","Thick"],"description":"`None` (default), `Thin`, or `Thick` drop shadow."},"show_pull_quote":{"type":"boolean","description":"If true, the video's featured pull quote renders alongside the embed."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/list_templates":{"post":{"operationId":"list_templates","summary":"list templates","description":"List the workspace's video templates — reusable recipes that drive both auto-assembly and chat-driven video creation. Returns id, name, whether the template carries a direction prompt (if set, videos assemble with AI), whether it pins an intro clip and/or an outro clip, and whether it is the workspace default. Use this when the user names a template (\"our Customer Spotlights template\") or asks \"what templates do we have?\". Pass the matching template's id to `create_storyboard` (template_id) so the new storyboard inherits the template's settings and editorial direction. Results carry `returned` (rows in this payload), `matched` (how many exist), and `truncated`; when `truncated` is true the list was capped and more exist than are shown.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/list_uploaded_clips":{"post":{"operationId":"list_uploaded_clips","summary":"list uploaded clips","description":"List the standalone uploaded clips in this workspace (animated logos, branded outros, intro cards, stats overlays, etc.) that can be dropped into a storyboard via `add_scene` (pass clip_id without reply_id) or pinned on a template via `update_template intro_clip_id` / `outro_clip_id`. Returns id, title, format (video/audio), and duration. Call this when the user references an uploaded clip by name — match the title and use the id. Results carry `returned` (rows in this payload), `matched` (how many exist), and `truncated`; when `truncated` is true the list was capped and more exist than are shown.","tags":["Read tools"],"x-scope":"read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/set_template_prompt":{"post":{"operationId":"set_template_prompt","summary":"set template prompt","description":"Set the AI direction prompt on a workspace template (addressed by template_id). The prompt is overwritten, not merged; an empty string clears it.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["template_id","direction_prompt"],"properties":{"template_id":{"type":"integer","description":"Template id (the bound subject)."},"direction_prompt":{"type":"string","description":"Structure, pacing, tone, and duration direction. Empty string clears it (standard logo → per-question clips → logo outro, full-clip playback)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/update_template":{"post":{"operationId":"update_template","summary":"update template","description":"Update a workspace template's settings (addressed by template_id) — aspect ratio, subtitles, soundtrack, polish flags, theme, colors. All fields optional; pass only what changes.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["template_id"],"properties":{"ai_direction":{"type":"boolean","description":"Master switch: assemble videos with AI using the saved direction prompt (spends AI credits). false keeps the prompt saved but assembles the standard structure — use it to turn AI assembly off without deleting the prompt."},"aspect_ratio":{"type":"string","enum":["square","portrait","landscape","automatic"]},"color_a":{"type":"string","description":"CSS hex color."},"color_b":{"type":"string","description":"CSS hex color."},"color_c":{"type":"string","description":"CSS hex color."},"color_d":{"type":"string","description":"CSS hex color."},"filler_word_removal":{"type":"boolean"},"include_soundtrack":{"type":"boolean"},"intro_clip_id":{"type":["integer","null"],"description":"Workspace-uploaded clip id to prepend as the opening scene of every video built from this template; pass null to clear."},"intro_logo":{"type":"boolean","description":"Standard-structure toggle: open with a logo scene naming the respondent. Applies unless the template's direction prompt overrides it; pinned opening scenes replace it regardless."},"lead_with_hook":{"type":"boolean","description":"Open the video with the strongest quote as a hook."},"logo_bg":{"type":"string","enum":["transparent","white","dark"],"description":"Logo-scene background."},"name":{"type":"string","maxLength":191},"outro_clip_id":{"type":["integer","null"],"description":"Workspace-uploaded clip id to append as the final scene of every video built from this template; pass null to clear."},"outro_logo":{"type":"boolean","description":"Standard-structure toggle: close with a logo scene. Applies unless the template's direction prompt overrides it; pinned closing scenes replace it regardless."},"question_text_scenes":{"type":"boolean","description":"Standard-structure toggle: introduce each question's clips with a text scene showing the question. Applies unless the template's direction prompt overrides it."},"shorten_word_gaps":{"type":"boolean"},"show_subtitles":{"type":"boolean"},"song_id":{"type":["integer","null"],"description":"Stock soundtrack id; null to clear. Replaces a custom-uploaded soundtrack if the template has one (see has_custom_soundtrack in list_templates)."},"soundtrack_volume":{"type":"number","description":"0.0–1.0 background music volume."},"studio_sound":{"type":"boolean"},"theme_type":{"type":"string","description":"Theme class name."},"video_bg_blur_amount":{"type":"integer"},"video_bg_effect":{"type":"string","description":"\"off\", \"blur\", \"remove\", or \"replace\"."},"video_frame":{"type":"string","description":"\"zoom\" or \"fit\"."},"watermark_logo_bg":{"type":"string","enum":["transparent","white","dark"],"description":"Corner-watermark background."},"word_gap_threshold":{"type":"number","description":"Word-gap shorten threshold, seconds."},"caption_preset":{"type":"string","enum":["theme_default","hormozi","tiktok","studio_label","flashcard","comic_book","lift","sticker_pop","punch_in","skewed","zoom_in_bold","zoom_out_bold","karaoke_classic","karaoke_one_word","underline_sweep","pop","future_dim","zoom_in_clean","zoom_out_clean","glow","paper_trail","typewriter","console","brandline","editorial","executive","calm","quiet_focus","cctv","clean"],"description":"Apply a named caption preset (resets caption_* fields to that preset; any other caption_* fields you pass then override it). Use for \"use Hormozi-style captions\", or to match a customer's brand/tone and the video's purpose. Use the internal key, matching the displayed name or visual description below. Presets are grouped by register: pick the family the brief calls for, then the preset within it whose appearance and keywords best fit.\nOn-brand — follows the workspace theme\n  theme_default (Theme Default): Native theme typography and caption treatments; follows the selected theme. [default, on-brand, safe, professional, neutral, conservative]\nHigh energy — bold, punchy, kinetic; social, TikTok/Reels/Shorts, creator, ads\n  hormozi (Hormozi): Heavy uppercase white text, yellow active words, outlines and bouncing emphasis. [high-energy, hype, tiktok, reels, shorts, fitness, coaching, marketing, ads, creator]\n  tiktok (TikTok): Condensed bold uppercase white text, red word boxes and outlines. [tiktok, viral, high-energy, reels, shorts, creator, Pro font]\n  flashcard (Flashcard): One heavy uppercase black word at a time on a white card, zooming in. [high-energy, launch, hook, tiktok, reels, shorts, monochrome, one-word]\n  comic_book (Comic Book): Handwritten uppercase lettering with thick outlines; white upcoming words become lime, with comic phrase motion. [comic, playful, illustrated, hand-drawn, pop-art, Pro font]\n  sticker_pop (Sticker Pop): Rounded dark lettering on pink boxes, orange word highlights and a comic tilt/pop. [playful, creator, lifestyle, promo, pink, sticker, fun]\n  skewed (Skewed): Tilted heavy uppercase lettering with a blue sweeping underline and phrase fades. [skewed, tilted, sweeping, edgy, dynamic, urban, music, streetwear, gen-z]\n  zoom_in_bold (Bold Swell): One heavy outlined uppercase white word at a time, swelling into place. [cinematic, dramatic, swell, one-word]\n  zoom_out_bold (Bold Slide): One heavy outlined uppercase white word at a time, sliding up into place. [cinematic, dramatic, slide, rise, one-word]\n  pop (Pop): Rounded playful lettering with pink active-word boxes and bouncing emphasis. [playful, fun, lively, youthful, lifestyle, casual]\nBalanced — readable and versatile; explainer, educational, demo\n  studio_label (Bold): White Outfit on a vivid blue pill; phrase zooms in and upcoming words brighten. [confident, blue, prominent]\n  lift (Lift): Large white Outfit rises into view; mint active words gently pop, with a drop shadow. [upbeat, recruiting, saas, launch, customer-story, mint, modern]\n  punch_in (Punch In): White bold text on translucent rounded boxes with soft shadow and a zoom-through transition. [zoom, promo, announcement, modern]\n  karaoke_classic (Karaoke): Readable Montserrat on a pill background, with a blue fading active word. [karaoke, engaging, balanced, educational, general, versatile]\n  karaoke_one_word (Karaoke One Word): One bold word at a time with a blue highlight box. [focus, rhythmic, minimal-words, quotes, emphasis, one-word]\n  underline_sweep (Underline Sweep): Uppercase white Montserrat with a cyan underline that sweeps across the active word. [tutorial, demo, blue]\n  zoom_in_clean (Clean Swell): One rounded white word at a time, with a drop shadow, swelling into place. [clean, swell, one-word]\n  zoom_out_clean (Clean Slide): One rounded white word at a time, with a drop shadow, sliding up into place. [clean, slide, rise, one-word]\nRefined — elegant, premium, editorial; serif and atmospheric\n  future_dim (Ticker Tape): Black Playfair serif on white cards, pale-yellow word boxes and a phrase fade/zoom. [ticker-tape, news, editorial, serif, paper, cards, highlighted, premium, Pro font]\n  glow (Glow): Soft purple active-word glow and shadow, with dim upcoming words and slow fades. [elegant, atmospheric, premium, cinematic, beauty, luxury, wellness]\n  paper_trail (Paper Trail): Dark Lato on warm paper-colored boxes, with a yellow marker highlight. [coaching, advice, educational, paper, warm, marker]\n  editorial (Editorial): Large cream serif lettering with a fading active-word color and soft shadow. [editorial, refined, elegant, serif, founder, hospitality, storytelling, premium, Pro font]\nTechy — monospace, terminal and typewriter looks; developer and startup\n  typewriter (Typewriter): Left-aligned monospace text in a centered translucent strip; words appear one by one. Alignment is preset-specific, not an adjustable field. [typewriter, techy, retro, monospace, left-aligned, reveal, editorial, developer, indie, startup]\n  console (Console): Monospace over a frosted full-width band, with an orange sweeping underline. [console, terminal, code, monospace, technical, frosted]\nRestrained — professional, corporate, formal; testimonial and B2B\n  brandline (Brandline): White Inter with a simple active-word underline and soft shadow. [on-brand, case-study, product]\n  executive (Executive): Playfair serif on a translucent black strip; words reveal with a marker highlight. [professional, formal, customer-story, internal-communications, conservative, Pro font]\n  calm (Calm): Black Montserrat on pale-gray rounded boxes; dim words gently brighten without changing accent color. [calm, measured, testimonial, conversational]\n  quiet_focus (Quiet Focus): Bold Lato on a dark rounded box; upcoming words brighten slowly. [training, educational, guided, calm, focused]\n  cctv (CCTV): Light Inter on a translucent black strip; dim upcoming words, no phrase motion. [cctv, surveillance, security-camera]\n  clean (Clean): Plain white Inter, modest phrasing and a simple phrase fade; no box or highlight. [clean, professional, testimonial, formal, b2b]"},"caption_size":{"type":"integer","minimum":50,"maximum":200,"description":"Caption Size percentage: named presets use a shared 40px base at 1920×1080; Theme Default uses its theme base. Square/portrait apply a further 90% multiplier. 150 means 1.5× the base."},"caption_width":{"type":"integer","minimum":30,"maximum":100,"description":"Maximum caption box width within the caption area. Named presets use a centered area 70% of landscape canvas width, 80% of square/portrait. Narrower values increase wrapping."},"caption_max_words":{"type":"integer","minimum":1,"maximum":20,"description":"Max words shown at once; 1–3 gives Hormozi-style word-by-word captions."},"caption_lines":{"type":"integer","minimum":1,"maximum":3,"description":"Balance each phrase into this many lines, with at least two words per line when possible. Does not change phrase length; use caption_max_words for that. Narrow widths can wrap into additional lines."},"caption_pill_opacity":{"type":"integer","minimum":0,"maximum":100,"description":"Opacity of the phrase background box or frosted backdrop, from 0% transparent to 100% opaque."},"caption_highlight_style":{"type":"string","enum":["none","recolor","box","underline","pill","glow","marker","underline_sweep"],"description":"Active-word treatment. recolor uses the active-word color; marker draws a low stroke. underline_sweep needs a non-instant word animation (prefer fade) to sweep; instant makes it appear/disappear without sweeping."},"caption_background_style":{"type":"string","enum":["none","solid","rounded","pill"],"description":"Phrase background box: none, solid rectangle, rounded rectangle, or pill."},"caption_scrim":{"type":"string","enum":["none","gradient","frosted"],"description":"Full-width caption backdrop: none/gradient/frosted."},"caption_outline_style":{"type":"string","enum":["none","thin","thick","medium"],"description":"Letter outline thickness; uses the shared outline/shadow color."},"caption_shadow_style":{"type":"string","enum":["none","drop","soft"],"description":"Letter shadow: none, soft halo, or offset drop shadow; uses the outline/shadow color."},"caption_group_animation":{"type":"string","enum":["none","fade","fade_zoom","zoom_through","comic_pop","zoom_in","zoom_out","rise","swell"],"description":"Whole-phrase motion on entrance/exit, independent of active-word motion; rise slides upward, comic_pop tilts/pops, zoom_in/out move scale inward/outward, swell bumps the phrase up as it lands then holds still."},"caption_word_animation":{"type":"string","enum":["instant","fade","gentle_pop","bounce"],"description":"Active-word transition: instant switches immediately; fade smoothly changes highlight/opacity; gentle_pop adds a small scale pulse; bounce adds an elastic pulse. Use fade for a sweeping underline."},"caption_animation_speed":{"type":"string","enum":["slow","normal","fast"],"description":"Speed of phrase and word transitions. Slow lengthens transitions, clamped to the available word/phrase timing."},"caption_future_word_style":{"type":"string","enum":["none","dim","recolor","hidden"],"description":"Upcoming words: none shows normal text; dim starts at 40% opacity; recolor uses the independent upcoming-word color (default scene Accent); hidden reveals words when spoken. Spoken words return to Text; active-word styling applies independently."},"caption_rotation_angle":{"type":"integer","minimum":-10,"maximum":10,"description":"Caption Angle in degrees: negative tilts counterclockwise, positive clockwise."},"caption_text_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_highlight_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_future_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_pill_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_effect_color":{"type":"string","enum":["a","b","c","d","white","black","scene_text","scene_accent"],"description":"Palette slot, not a colour name — \"b\" means color_b, not blue: a/b/c/d are the brand colours color_a–color_d, white/black are fixed, and scene_text/scene_accent follow the video or audio scene Text/Accent. For a specific colour use the matching *_hex field; a *_hex override takes precedence, so clear it when selecting a slot. The write echoes resolved_colors — check it before telling the user what colour they got."},"caption_text_color_hex":{"type":"string","description":"Custom caption text colour, CSS hex (overrides the caption_text_color slot)."},"caption_highlight_color_hex":{"type":"string","description":"Custom active-word colour, CSS hex."},"caption_future_color_hex":{"type":"string","description":"Custom upcoming-word colour, CSS hex. Used when caption_future_word_style is recolor; defaults to the scene accent."},"caption_pill_color_hex":{"type":"string","description":"Custom caption background colour, CSS hex."},"caption_effect_color_hex":{"type":"string","description":"Custom outline and shadow colour, CSS hex."},"template_id":{"type":"integer","description":"Template id (the bound subject)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/tighten":{"post":{"operationId":"tighten","summary":"tighten","description":"Apply storyboard-wide polish in one step: remove filler words, shorten word gaps, and/or adjust the gap threshold. Each parameter is optional — pass only what you want to change. The natural \"make it tighter\" tool. The change is reversible with a single Cmd+Z.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id"],"properties":{"storyboard_id":{"type":"integer"},"remove_filler_words":{"type":"boolean","description":"Mute \"um\", \"uh\", \"like\", and other filler in every media scene."},"shorten_gaps":{"type":"boolean","description":"Trim long silences between words across every media scene."},"gap_threshold":{"type":"number","description":"Silence length (seconds) that counts as a gap. Range 0.2–2.0. Only takes effect when shorten_gaps is on."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/find_replace":{"post":{"operationId":"find_replace","summary":"find replace","description":"Replace every occurrence of a word or phrase across every media scene's transcript. Use for fixing a misspelled name, swapping one product term for another, or scrubbing a phrase the user wants removed. preserve_case mirrors the original casing per occurrence.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["storyboard_id","find","replace"],"properties":{"storyboard_id":{"type":"integer"},"find":{"type":"string","description":"Phrase to search for. Whole-word match, case-insensitive."},"replace":{"type":"string","description":"Replacement phrase. Pass an empty string to delete the matched phrase."},"preserve_case":{"type":"boolean","description":"If true, transfer the case of each match to its replacement (Foo → Bar, FOO → BAR, foo → bar)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v2/tools/mute_words":{"post":{"operationId":"mute_words","summary":"mute words","description":"Mute or unmute words on a media scene by transcript index. Pass `mute: true` to silence (default), `mute: false` to restore. Use after `get_scene` reveals the index of the word(s) you want to silence. Word indices are zero-based positions in the clip's transcript.","tags":["Write tools"],"x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scene_id","word_indices"],"properties":{"scene_id":{"type":"integer"},"word_indices":{"type":"array","items":{"type":"integer"},"description":"Zero-based word positions in the clip transcript."},"mute":{"type":"boolean","description":"true to mute, false to unmute. Defaults to true."},"storyboard_id":{"type":"integer","description":"Optional. When set, the scene must belong to this storyboard — scopes the edit (recommended for API/MCP callers)."}}}}}},"responses":{"200":{"description":"Tool result.","content":{"application/json":{"schema":{"type":"object","required":["tool","result"],"properties":{"tool":{"type":"string"},"result":{"type":"object","description":"Tool-specific payload, or the truncated-write summary below when a successful write's result exceeded the 256 KB limit.","properties":{"response_truncated":{"type":"boolean","description":"Present and true only when the tool succeeded but its result was dropped for exceeding the size limit. The mutation is committed; read the resource back rather than retrying the write."}}}}}}}},"400":{"description":"Request body failed JSON-Schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API access disabled (`api_disabled`), the key scope is insufficient for this tool (`forbidden_scope`), or the access holding the key is reviewer-level and the tool makes editor changes (`forbidden_role`). Nothing was written in any case.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No tool with this name is exposed on the v2 surface.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Response exceeded the 256 KB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A text value exceeded the length its column allows (`value_too_long`). String properties carry `maxLength` where a bound exists — respect it rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}