{"openapi":"3.1.0","info":{"title":"VIDEO AI ME API","version":"1.0.0","description":"Programmatic access to VIDEO AI ME skills: make video ads, publish them to connected social accounts, and check run status. Authenticate every skill and run endpoint with an API key (Authorization: Bearer va_live_...). Keys are managed at /api/v1/keys by a logged-in Pro or Premium user. Costs are quoted in credits; 1 credit = 1 cent."},"servers":[{"url":"https://videoai.me"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"API key in the va_live_... format, created at /api/v1/keys. Requires an active Pro or Premium subscription."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"issues":{"type":"array","description":"Validation issues, present on 400 responses."}}}}},"FlowValue":{"description":"One step input value: a literal, or a dot-path reference into an earlier step's result (asynchronous steps complete with { status, deliverable }, so references look like \"deliverable.files.0.url\").","oneOf":[{"type":"object","required":["literal"],"properties":{"literal":{}},"additionalProperties":false},{"type":"object","required":["fromStep","path"],"properties":{"fromStep":{"type":"string","minLength":1},"path":{"type":"string","minLength":1}},"additionalProperties":false}]},"FlowStep":{"type":"object","required":["id","skillId","input"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,63}$","description":"Unique slug within the flow."},"skillId":{"type":"string","description":"A skill id from GET /api/v1/skills."},"input":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/FlowValue"}},"dependsOn":{"type":"array","items":{"type":"string"},"description":"Earlier step ids this step waits on. References in input imply dependencies on their own."}}},"FlowDefinition":{"type":"object","required":["name","steps"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":500},"steps":{"type":"array","minItems":1,"maxItems":10,"items":{"$ref":"#/components/schemas/FlowStep"},"description":"Topologically ordered: every dependency and reference must point at an earlier step."}}},"list_templates_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists every video template the platform can run: id, what it makes, supported durations and aspect ratios, and the honest credit cost range (1 credit = 1 cent). Free and read-only; call it before proposing a maker skill so cost quotes are accurate."},"list_models_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists every generation model the platform can run: id, kind (video or image), display name, supported resolutions with the honest cost basis (per-second credits for video, per-image credits for image, 1 credit = 1 cent), clip length windows, and capability flags (start-frame animation, text-to-video, baked-in narration, end-frame interpolation). Free and read-only; call it before make_image_to_video or any model choice so model ids and cost quotes are accurate."},"list_actors_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists the user's saved actors with their looks (id, style, status, aspect ratio). Only looks with status \"completed\" can be animated; anything else is still generating or failed. Free and read-only. Call it before make_talking_head: that skill needs a completed look id from here."},"list_voices_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists the available voices: the platform voice library plus the user's own cloned voices. Free and read-only; the voiceId values work directly with make_voiceover."},"get_brand_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Reads the user's saved brand memory: business facts, target customer, tone of voice, banned words, preferred actors and voices, platform handles and notes. Free and read-only; check it before writing any script or caption so the output matches the brand."},"update_brand_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"businessName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"websiteUrl":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"products":{"maxItems":50,"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"targetCustomer":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"toneOfVoice":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"languages":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":40}},"bannedWords":{"maxItems":200,"type":"array","items":{"type":"string","maxLength":80}},"preferredActorIds":{"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"preferredVoiceIds":{"maxItems":50,"type":"array","items":{"type":"string","maxLength":80}},"platformHandles":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","maxLength":120}},"goals":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":300}},"notes":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}]}},"description":"Saves brand facts the user shares (business name, products, target customer, tone of voice, banned words, preferred actors/voices, platform handles, notes) so future runs stay on brand. Only the fields you pass change. Free; confirm with the user before overwriting something they saved earlier."},"list_platform_accounts_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists the social accounts the user has connected for publishing: platform, accountId, username and connection status. Free and read-only. Call it before publish_video or schedule_post: those skills need accountId values from here, and accounts marked needs_reauth cannot receive posts."},"analyze_website_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"url":{"type":"string","minLength":4,"maxLength":500,"description":"The website to analyze, e.g. https://example.com (a bare domain also works)."}},"required":["url"],"description":"Reads the user's website and drafts their brand memory (business name, products, target customer, tone of voice, languages) plus three starter video pitches. Use it when brand memory is empty or thin and the user has a website. Free and read-only: it returns a DRAFT and saves nothing. Show the draft to the user as an editable summary, let them correct it, and save only what they confirm with update_brand. The three pitches are conversation starters, not commitments."},"make_ugc_ad_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"productName":{"type":"string","minLength":1,"maxLength":80},"script":{"type":"string","minLength":1,"maxLength":500},"actorDescription":{"type":"string","maxLength":90},"aspect":{"default":"9:16","type":"string","enum":["9:16","16:9"]},"durationSeconds":{"default":30,"type":"integer","minimum":10,"maximum":120},"hook":{"type":"string","maxLength":140},"voice":{"default":"female","type":"string","enum":["male","female"]},"setting":{"default":"bedroom","type":"string","enum":["bedroom","kitchen","outdoors","desk"]},"creatorPhotoUrl":{"type":"string","maxLength":2000},"productPhotoUrl":{"type":"string","maxLength":2000},"avoid":{"type":"string","maxLength":200},"confirmed":{"type":"boolean"}},"required":["productName","script"],"description":"Creates a talking-head UGC ad: one creator filming themselves at home, speaking a script written from your brief. creatorPhotoUrl and productPhotoUrl accept an https URL or the assetId of a saved image asset (list_assets). Spends real video credits (1 credit = 1 cent), so always tell the user the estimated cost before starting, and only pass confirmed: true after they agree. The run pauses at a storyboard approval step before the expensive clip phase; check progress with check_run and approve with approve_storyboard (or the approval URL). A finished ad typically takes 6 to 25 minutes."},"make_product_ad_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"productName":{"type":"string","minLength":1,"maxLength":80},"brief":{"type":"string","minLength":1,"maxLength":600},"productImages":{"default":[],"maxItems":4,"type":"array","items":{"type":"string","maxLength":2000}},"aspect":{"default":"9:16","type":"string","enum":["9:16","16:9"]},"durationSeconds":{"default":15,"type":"integer","minimum":5,"maximum":20},"style":{"default":"studio-minimal","type":"string","enum":["studio-minimal","natural-textures","lifestyle-context"]},"avoid":{"type":"string","maxLength":200},"confirmed":{"type":"boolean"}},"required":["productName","brief"],"description":"Creates a polished product ad from a short brief: storyboard, key visuals, then one continuous video with sound. The first product image is used as the visual reference; productImages entries accept an https URL or the assetId of a saved image asset (list_assets). Spends real video credits (1 credit = 1 cent), so always tell the user the estimated cost before starting, and only pass confirmed: true after they agree. The run pauses at a storyboard approval step before video credits are spent; check progress with check_run and approve with approve_storyboard (or the approval URL). A finished ad typically takes 6 to 25 minutes."},"make_explainer_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"topic":{"type":"string","minLength":1,"maxLength":80},"brief":{"type":"string","minLength":1,"maxLength":600},"aspect":{"default":"9:16","type":"string","enum":["9:16","16:9"]},"durationSeconds":{"default":30,"type":"integer","minimum":10,"maximum":40},"narratorVoice":{"default":"female","type":"string","enum":["male","female"]},"productPhotoUrl":{"type":"string","format":"uri"},"avoid":{"type":"string","maxLength":200},"confirmed":{"type":"boolean"}},"required":["topic","brief"],"description":"Creates a paper-collage explainer video with baked-in narration from a topic and a short brief (a narrated scene-by-scene script, one collage board per scene, then animated clips cut together). Spends real video credits (1 credit = 1 cent), so always tell the user the estimated cost before starting, and only pass confirmed: true after they agree. The run pauses at a board approval step before video credits are spent; check progress with check_run and approve with approve_storyboard (or the approval URL). A finished explainer typically takes 6 to 25 minutes."},"make_talking_head_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"actorLookId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"script":{"type":"string","maxLength":600},"voiceId":{"type":"string","minLength":1},"durationSeconds":{"default":5,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"draftRunId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"confirmed":{"type":"boolean"}},"required":["actorLookId"],"description":"Animates one of the user's saved actor looks into a talking-head video clip (5 or 10 seconds). Best practice is draft first, film second: pass the script plus a voiceId from list_voices to get a cheap draft (the actor look image plus the script spoken in that voice, paid from the monthly voice minutes cap, no video credits) - ALWAYS show the draft to the user and get their approval of the look, voice and script before filming. Once approved, call again with draftRunId and confirmed: true to film the same validated script; filming spends real video credits (1 credit = 1 cent), so confirm the estimated cost with the user first. Call list_actors first to pick a completed look id. Without a voiceId the clip films directly; the filmed clip itself is silent, so pair it with make_voiceover (or the draft audio) for the spoken track. Poll the result with check_run."},"make_image_to_video_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"imagePrompt":{"type":"string","minLength":1,"maxLength":4000},"imageUrl":{"type":"string","format":"uri"},"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"videoPrompt":{"type":"string","minLength":1,"maxLength":4000},"model":{"default":"seedance25","type":"string","minLength":1},"durationSeconds":{"default":8,"type":"integer","minimum":1,"maximum":30},"aspect":{"default":"9:16","type":"string","enum":["9:16","16:9"]},"resolution":{"default":"720p","type":"string","enum":["480p","720p","1080p"]},"numImages":{"default":1,"type":"integer","minimum":1,"maximum":4},"stage1RunId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"confirmed":{"type":"boolean"}},"required":["videoPrompt"],"description":"Makes a video the image-first way: great videos start from a great first frame, so generate the image cheap, get the user's approval on it, then animate. Stage 1 (imagePrompt): generates start-frame candidates from the monthly image quota, no video credits spent, and returns them with stage2EstimateCents; ALWAYS show the image to the user and get their approval of the frame before the video stage. Stage 2 (imageUrl or assetId): animates the approved frame; this spends real video credits (1 credit = 1 cent), so quote the cost and pass confirmed: true plus the stage1RunId only after the user agrees. Poll the video with check_run. Defaults to the strongest start-frame model by capability (start plus end frame support and the longest clips); pass model to pick another start-frame capable model."},"make_voiceover_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":5000},"voiceId":{"type":"string","minLength":1},"clipId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["text","voiceId"],"description":"Turns text into a spoken audio track with one of the user's voices, and returns the audio URL. Call list_voices first for a voiceId (platform library or a voice cloned with clone_voice). This is what pairs with make_talking_head, whose clips are silent, before merge_videos stitches the final cut. It spends no credits: it draws from the monthly voice minutes cap instead (roughly one minute per 750 characters), a separate allowance from the credit budget, so a user with credits left can still run out of voice minutes."},"add_captions_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"clipId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"runId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"description":"Transcribes a completed video and burns word-level captions into the picture, returning the captioned video URL. Free. Captions are opt-in: ask the user before adding them. Pass the clipId of a finished clip, or the runId of a completed maker skill run."},"merge_videos_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"videoUrls":{"minItems":2,"maxItems":10,"type":"array","items":{"type":"string","format":"uri"}},"runIds":{"minItems":2,"maxItems":10,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"clipIds":{"minItems":2,"maxItems":10,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"confirmed":{"type":"boolean"}},"description":"Stitches 2 to 10 finished videos into one file, in the exact order given. Included at no credit cost. Order matters: ALWAYS present the ordered list of clips to the user and confirm it before merging. Pass direct videoUrls, runIds of completed maker skill runs, or clipIds of finished clips, then poll the merged result with check_run."},"create_actor_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"originalPath":{"type":"string","minLength":1},"processedPath":{"type":"string","minLength":1},"skipLooks":{"default":false,"type":"boolean"}},"required":["name","originalPath","processedPath"],"description":"Creates a reusable actor from a photo in the user's images storage, and launches its 4 automatic looks. To upload a photo you were given, POST /api/v1/uploads (Bearer key) with { kind: \"image\", filename }, PUT the bytes to the returned uploadUrl, then pass the returned storagePath as BOTH originalPath and processedPath (processedPath is only a separately cropped copy when you have one). This draws one slot from the monthly custom actor cap plus 4 images from the monthly image quota, and the looks take a few minutes to finish generating: tell the user before starting, then check list_actors for the finished looks."},"clone_voice_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"consent":{"type":"boolean","const":true},"storagePath":{"type":"string","minLength":1},"name":{"type":"string","minLength":2,"maxLength":50},"description":{"type":"string","maxLength":500},"contentType":{"type":"string"}},"required":["consent","storagePath","name"],"description":"Clones a custom voice from an audio sample in the user's voice sample storage. To upload a sample you were given, POST /api/v1/uploads (Bearer key) with { kind: \"voice\", filename }, PUT the bytes to the returned uploadUrl, then pass the returned storagePath here. REQUIRED: confirm with the user that the voice is their own or that they have the speaker's explicit consent, and only then pass consent: true - never clone a voice without that confirmation. Draws one slot from the monthly custom voice cap. The cloned voiceId works with make_voiceover afterwards."},"approve_storyboard_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"approve":{"type":"boolean","const":true}},"required":["runId","approve"],"description":"Approves the storyboard frames of a paused maker run (make_ugc_ad, make_product_ad, make_explainer) and starts the paid clip phase, exactly like approving in the app. Approving commits real video credits: ALWAYS show the user the frames (or the approval URL from check_run) and get their explicit approval first, then call with approve: true and the runId. Free to call; the clip spend was already quoted when the run started. Keep polling with check_run afterwards."},"publish_video_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"confirmPlatforms":{"type":"boolean","const":true},"targets":{"minItems":1,"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"username":{"type":"string"}},"required":["platform","accountId"]}},"content":{"type":"string","maxLength":5000},"media":{"type":"object","properties":{"source":{"type":"string","enum":["merge_job","template_run","upload","url"]},"sourceId":{"type":"string"},"storagePath":{"type":"string"},"url":{"type":"string","maxLength":2000,"format":"uri"}},"required":["source"]},"publishNow":{"default":true,"type":"boolean"},"scheduledAt":{"type":"string"},"timezone":{"default":"UTC","type":"string"}},"required":["confirmPlatforms","targets","media"],"description":"Publishes or schedules a finished video to the user's connected social accounts. Publishing is an outward action on real accounts: ALWAYS confirm the exact platform list with the user first, and only then call with confirmPlatforms: true. Costs no credits. Use check_run on a maker skill first if the video is still generating."},"schedule_post_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"confirmPlatforms":{"type":"boolean","const":true},"targets":{"minItems":1,"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"username":{"type":"string"}},"required":["platform","accountId"]}},"content":{"type":"string","maxLength":5000},"media":{"type":"object","properties":{"source":{"type":"string","enum":["merge_job","template_run","upload"]},"sourceId":{"type":"string"},"storagePath":{"type":"string"}},"required":["source"]},"useQueue":{"default":false,"type":"boolean"},"scheduledAt":{"type":"string"},"timezone":{"default":"UTC","type":"string"}},"required":["confirmPlatforms","targets","media"],"description":"Schedules a finished video onto the user's posting queue (useQueue: true takes the next free slot of their weekly schedule) or at an explicit time (scheduledAt). Posting is an outward action on real accounts: ALWAYS confirm the exact platform list and the timing with the user first, and only then call with confirmPlatforms: true. Costs no credits."},"get_performance_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"limit":{"default":50,"type":"integer","minimum":1,"maximum":100}},"description":"Reads how the user's published posts performed: per-platform delivery status, metrics (views, likes, comments, shares, clicks) and totals per post. Read-only, free and safe to call any time; metrics refresh with the daily analytics sync."},"list_ad_accounts_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists the ad accounts the user has connected for paid campaigns: each connected account (accountId, platform, name) plus the platform ad accounts under it (adAccountId, name, currency). Free and read-only. Call it before launch_ad: that skill needs an accountId and adAccountId pair from here. Only works on accounts where ads access is enabled."},"launch_ad_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"confirmLaunch":{"type":"boolean","const":true},"accountId":{"type":"string","minLength":1},"adAccountId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1,"maxLength":200},"goal":{"type":"string","minLength":1},"media":{"type":"object","properties":{"source":{"type":"string","enum":["merge_job","template_run","upload","url"]},"sourceId":{"type":"string"},"storagePath":{"type":"string"},"url":{"type":"string","maxLength":2000,"format":"uri"}},"required":["source"]},"headline":{"type":"string","maxLength":300},"body":{"type":"string","maxLength":2000},"linkUrl":{"type":"string","format":"uri"},"callToAction":{"type":"string","maxLength":60},"budgetAmount":{"type":"number","exclusiveMinimum":0},"budgetType":{"type":"string","enum":["daily","lifetime"]},"startDate":{"type":"string"},"endDate":{"type":"string"},"countries":{"maxItems":50,"type":"array","items":{"type":"string","minLength":2,"maxLength":2}},"ageMin":{"type":"integer","minimum":13,"maximum":100},"ageMax":{"type":"integer","minimum":13,"maximum":100},"gender":{"type":"string","enum":["all","male","female"]},"interests":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id"]}},"cities":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"radius":{"type":"number"},"distance_unit":{"type":"string","enum":["kilometer","mile"]}},"required":["key"]}},"regions":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"key":{"type":"string"}},"required":["key"]}},"organizationId":{"type":"string"},"dsaBeneficiary":{"type":"string"},"dsaPayor":{"type":"string"},"activate":{"default":false,"type":"boolean"}},"required":["confirmLaunch","accountId","adAccountId","name","goal","media","budgetAmount"],"description":"Turns a finished video into a paid ad campaign on one of the user's connected ad accounts. Call list_ad_accounts first to get the accountId and adAccountId values this skill needs. The budget is the user's OWN ad spend, billed by the ad platform to their ad account, never platform credits. The campaign is created PAUSED unless activate is explicitly true, so nothing spends by surprise. Requires confirmLaunch: true: ALWAYS present the full campaign summary (platform, ad account, objective, budget, schedule, targeting, creative) and get the user's explicit approval before calling. Only works on accounts where ads access is enabled."},"pause_ad_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"campaignId":{"type":"string","minLength":1}},"required":["campaignId"],"description":"Pauses an entire ad campaign so it stops spending the user's own ad budget; the paused status cascades through the campaign's ad sets and ads. Free and safe: pausing never deletes anything, and the campaign can be resumed from the ads manager. Only works on accounts where ads access is enabled."},"get_ad_performance_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"campaignId":{"type":"string","minLength":1},"fromDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"toDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["campaignId"],"description":"Reads performance for one of the user's ad campaigns: spend, impressions, clicks and the daily timeline over an optional date range. Read-only and free to call; the spend figures are the user's own ad spend as reported by the ad platform, not platform credits. Only works on accounts where ads access is enabled."},"create_flow_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":500},"steps":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,63}$"},"skillId":{"type":"string","minLength":1},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"literal":{}},"required":["literal"],"additionalProperties":false},{"type":"object","properties":{"fromStep":{"type":"string","minLength":1},"path":{"type":"string","minLength":1}},"required":["fromStep","path"],"additionalProperties":false}]}},"dependsOn":{"type":"array","items":{"type":"string"}}},"required":["id","skillId","input"]}}},"required":["name","steps"],"description":"Saves a reusable flow: a named pipeline of up to 10 skill steps that runs as one unit. Steps run in the order listed and reference earlier steps' outputs with {\"fromStep\": \"step-id\", \"path\": \"dot.path\"} values instead of literals: asynchronous maker steps complete as { status: \"completed\", deliverable }, so paths like \"deliverable.files.0.url\" feed a finished video into the next step, while synchronous steps expose their raw result (for example \"postUrl\"). Literals are written as {\"literal\": value}. References can also sit one level inside an object or array literal: any {\"fromStep\", \"path\"} node directly inside a literal value resolves at run time, which is how a publish step's media object takes a finished video via {\"source\": \"url\", \"url\": {\"fromStep\": \"make-ad\", \"path\": \"deliverable.files.0.url\"}}. Every step is validated against the real skill registry at save time. Building a flow is how you create a reusable skill for this brand: saved flows are reusable pipelines the user can run again and again with run_flow. Present the flow's steps and its total credit estimate (1 credit = 1 cent) to the user before running it."},"update_flow_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":500},"steps":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,63}$"},"skillId":{"type":"string","minLength":1},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"object","properties":{"literal":{}},"required":["literal"],"additionalProperties":false},{"type":"object","properties":{"fromStep":{"type":"string","minLength":1},"path":{"type":"string","minLength":1}},"required":["fromStep","path"],"additionalProperties":false}]}},"dependsOn":{"type":"array","items":{"type":"string"}}},"required":["id","skillId","input"]}},"flowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["name","steps","flowId"],"description":"Replaces a saved flow's name, description and steps with a new definition (same shape as create_flow), re-validated against the skill registry. Use it to iterate on a flow conversationally: fetch it with get_flow, adjust the steps, and save. Only the flow's owner can update it. Free."},"list_flows_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists the user's saved flows: id, name, description, step count and credit estimate. Free and read-only. Saved flows are reusable pipelines; check here before building a new flow from scratch, and use get_flow to read one in full."},"get_flow_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"flowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["flowId"],"description":"Reads one saved flow in full: its complete step definition plus the credit estimate. Free and read-only. Use it when the user wants the same pipeline again with a change: read the definition, adjust it in conversation, and save with update_flow instead of rebuilding from scratch."},"run_flow_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"flowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"inputs":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"confirm":{"type":"boolean"},"confirmed":{"type":"boolean"}},"required":["flowId"],"description":"Starts a saved flow. Your saved flow is a parameterized skill: pass inputs to customize each run with per-step literal overrides keyed by step id then input field, for example { \"make-ad\": { \"brief\": \"Tonight's angle\" } } (reference inputs cannot be overridden). Without confirm: true it answers needs_confirmation with the run's total credit estimate (overrides included) and runs nothing; present that estimate to the user and start again with confirm: true only after they agree (1 credit = 1 cent). Once started, the flow runs step by step in the background: poll it with get_flow_run using the flowRunId, and come back later for long pipelines."},"run_flow_batch_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"flowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"variants":{"minItems":2,"maxItems":20,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"overrides":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["label","overrides"]}},"confirm":{"type":"boolean"},"confirmed":{"type":"boolean"}},"required":["flowId","variants"],"description":"Runs a saved flow as a batch of 2 to 20 variants: turn one proven flow into a testing batch by swapping hooks, actors, products, or languages systematically. Each variant carries a label and per-step literal-input overrides keyed by step id then input field, for example { \"label\": \"Spanish hook\", \"overrides\": { \"make-ad\": { \"script\": \"Hola! ...\" } } }. Only literal inputs can be overridden; reference inputs cannot. Without confirm: true it answers needs_confirmation with the total credit estimate plus a per-variant breakdown and starts nothing; present that per-variant table and the total to the user, then call again with confirm: true only after they agree (1 credit = 1 cent). Once started, every variant runs as its own flow run sharing one batchId: poll individual runs with get_flow_run using each runId, and come back later for long batches."},"get_flow_run_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"flowRunId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["flowRunId"],"description":"Checks a flow run started with run_flow: overall status, each step's state (keyed by step id, including awaiting_approval pauses), currentSteps, and the deliverables of completed steps keyed by step id. Same shape as GET /api/v1/flow-runs/{runId}. Polling also nudges the run forward, so this is how flows execute in the background: start with run_flow, come back later and poll here. Free and safe to poll every minute or two."},"save_asset_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"kind":{"type":"string","enum":["image","video","webpage","audio","other"]},"title":{"type":"string","minLength":1,"maxLength":200},"sourceUrl":{"type":"string","maxLength":2000,"format":"uri"},"storagePath":{"type":"string","minLength":1,"maxLength":500},"tags":{"default":[],"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":60}},"analysis":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["kind","title"],"description":"Saves a reusable asset (image, video, webpage, audio) to the user's asset library. Your asset library is your memory of reusable material: whenever the user shares a product photo, video, page or audio worth reusing, or you analyze one with analyze_asset, save it here with a meaningful title and tags so future conversations can find it with list_assets instead of asking the user again. Pass a public sourceUrl, or a storagePath: to save a local file the user gave you, POST /api/v1/uploads (Bearer key) with { kind, filename }, PUT the bytes to the returned uploadUrl, then save the returned storagePath here. Pass the analysis through when you already analyzed it. Free."},"list_assets_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"kind":{"type":"string","enum":["image","video","webpage","audio","other"]},"tag":{"type":"string","minLength":1,"maxLength":60},"search":{"type":"string","minLength":1,"maxLength":120},"limit":{"default":50,"type":"integer","minimum":1,"maximum":50}},"description":"Lists the user's saved assets (newest first, up to 50), optionally filtered by kind, tag, or a title text match, including any stored analysis. Stored assets also come back with a fresh 24 hour url you can hand straight to a maker skill. Free and read-only. Your asset library is your memory of reusable material: check list_assets for existing product photos, videos or pages before asking the user to re-upload or re-share anything."},"analyze_asset_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"url":{"type":"string","maxLength":2000,"format":"uri"},"kind":{"type":"string","enum":["image","video","webpage","audio","other"]}},"description":"Analyzes an asset so it can be reused in production: images get a vision analysis (subject, style, colors, visible text, suggested uses), videos get a transcription PLUS a visual description (what is on screen: subject, setting, framing, style), audio gets a transcription, and webpages get the site scrape plus brand draft. Analysis costs 1 to 3 credits depending on the kind (1 credit = 1 cent); webpage analysis is included at no cost. Pass an assetId to persist the analysis onto the saved asset, or a url plus kind for new material, then save_asset it with a meaningful title and tags so future conversations can reuse it."},"create_project_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200}},"description":"Creates a project: a reusable multi-clip video that clips are added to and then assembled into one final video. Free. Start here when the user wants to combine several clips into one video, then add finished clips with add_clip."},"get_project_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"projectId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["projectId"],"description":"Returns a project with its clips in order, each resolved to a playable video URL, plus the final video once assembled. Free and read-only. Use it to show the user the current clip order before reordering, trimming, or finalizing."},"list_projects_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"description":"Lists the user's projects (multi-clip video artifacts), newest first, with a clip count and status each. Free and read-only. Check here before creating a new project so an existing one can be reused."},"add_clip_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"projectId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"source":{"type":"object","properties":{"kind":{"type":"string","enum":["run","url","upload"]},"runId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"url":{"type":"string","format":"uri"},"storagePath":{"type":"string","minLength":1}},"required":["kind"]},"position":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["projectId","source"],"description":"Adds one clip to a project. Pass a finished run's runId (the usual case, straight from a completed maker skill), a direct video URL, or an owned upload path. Free. Appends at the end unless you set a position. Tell the user which clip you added so they can watch the project build up."},"reorder_clips_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"projectId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"orderedClipIds":{"minItems":1,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}},"required":["projectId","orderedClipIds"],"description":"Sets the order of a project's clips. Pass every clip id exactly once in the new order. Free. Present the new order to the user and confirm it before assembling, since order is how the final video plays."},"trim_clip_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"clipId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"trimStartSeconds":{"type":"number","minimum":0},"trimEndSeconds":{"type":"number","minimum":0}},"required":["clipId"],"description":"Records trim points (start and/or end seconds) on a project clip. Free. Trims are recorded on the project as metadata and are not yet applied when the project is assembled, so tell the user the trims are saved but the assembled video still uses each clip in full for now."},"remove_clip_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"clipId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["clipId"],"description":"Removes a clip from its project and renumbers the rest. Free. Use it to drop a clip the user does not want in the assembled video."},"finalize_project_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"projectId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"confirmed":{"type":"boolean"}},"required":["projectId"],"description":"Assembles a project into one final video by merging its clips in order. Included at no credit cost. ALWAYS present the clip order to the user and confirm it before finalizing. Returns a runId that you poll with check_run; when it completes the project is ready with a final video URL that can then be published with publish_video or captioned with add_captions."},"check_run_input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"skillRunId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"description":"Checks the status of a run started by another skill (pass the runId it returned) and returns the finished deliverable (video URL, cost, timing) when it completes. Free and safe to poll; generation runs typically take 6 to 25 minutes, so poll every minute or two rather than in a tight loop."}}},"paths":{"/api/v1/skills":{"get":{"operationId":"listSkills","summary":"List the available skills with schemas, costs and durations","responses":{"200":{"description":"The skill catalog.","content":{"application/json":{"schema":{"type":"object","required":["skills"],"properties":{"skills":{"type":"array","items":{"type":"object","required":["id","displayName","description","creditCostRange","durationBand","inputSchema"],"properties":{"id":{"type":"string","enum":["list_templates","list_models","list_actors","list_voices","get_brand","update_brand","list_platform_accounts","analyze_website","make_ugc_ad","make_product_ad","make_explainer","make_talking_head","make_image_to_video","make_voiceover","add_captions","merge_videos","create_actor","clone_voice","approve_storyboard","publish_video","schedule_post","get_performance","list_ad_accounts","launch_ad","pause_ad","get_ad_performance","create_flow","update_flow","list_flows","get_flow","run_flow","run_flow_batch","get_flow_run","save_asset","list_assets","analyze_asset","create_project","get_project","list_projects","add_clip","reorder_clips","trim_clip","remove_clip","finalize_project","check_run"]},"displayName":{"type":"string"},"description":{"type":"string"},"creditCostRange":{"type":"object","properties":{"minCents":{"type":"integer"},"maxCents":{"type":"integer"}}},"durationBand":{"type":"object","properties":{"p50Seconds":{"type":"number"},"p90Seconds":{"type":"number"}}},"inputSchema":{"type":"object"},"custom":{"type":"boolean","description":"True for the caller's own saved flows exposed as skills. These are per-user, so they appear in this listing (and over MCP) but never in this static spec."}}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API requires an active Pro or Premium subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/skills/{skillId}/run":{"post":{"operationId":"runSkill","summary":"Run a skill","description":"Starts a skill run. Maker skills spend real credits and may answer with status needs_confirmation, in which case the user must approve the estimated cost and the call is repeated with confirmed: true.","parameters":[{"name":"skillId","in":"path","required":true,"schema":{"type":"string","description":"A skill id from GET /api/v1/skills: either a registry skill (lowercase words joined by underscores, for example make_ugc_ad) or one of the caller's own saved flows, whose ids start with \"flow_\" and are equally valid here.","examples":["list_templates","list_models","list_actors","list_voices","get_brand"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"description":"The skill's own input object. Custom flow skills (\"flow_\" ids) take { inputs?, confirm? } instead of one of the schemas below.","oneOf":[{"$ref":"#/components/schemas/list_templates_input"},{"$ref":"#/components/schemas/list_models_input"},{"$ref":"#/components/schemas/list_actors_input"},{"$ref":"#/components/schemas/list_voices_input"},{"$ref":"#/components/schemas/get_brand_input"},{"$ref":"#/components/schemas/update_brand_input"},{"$ref":"#/components/schemas/list_platform_accounts_input"},{"$ref":"#/components/schemas/analyze_website_input"},{"$ref":"#/components/schemas/make_ugc_ad_input"},{"$ref":"#/components/schemas/make_product_ad_input"},{"$ref":"#/components/schemas/make_explainer_input"},{"$ref":"#/components/schemas/make_talking_head_input"},{"$ref":"#/components/schemas/make_image_to_video_input"},{"$ref":"#/components/schemas/make_voiceover_input"},{"$ref":"#/components/schemas/add_captions_input"},{"$ref":"#/components/schemas/merge_videos_input"},{"$ref":"#/components/schemas/create_actor_input"},{"$ref":"#/components/schemas/clone_voice_input"},{"$ref":"#/components/schemas/approve_storyboard_input"},{"$ref":"#/components/schemas/publish_video_input"},{"$ref":"#/components/schemas/schedule_post_input"},{"$ref":"#/components/schemas/get_performance_input"},{"$ref":"#/components/schemas/list_ad_accounts_input"},{"$ref":"#/components/schemas/launch_ad_input"},{"$ref":"#/components/schemas/pause_ad_input"},{"$ref":"#/components/schemas/get_ad_performance_input"},{"$ref":"#/components/schemas/create_flow_input"},{"$ref":"#/components/schemas/update_flow_input"},{"$ref":"#/components/schemas/list_flows_input"},{"$ref":"#/components/schemas/get_flow_input"},{"$ref":"#/components/schemas/run_flow_input"},{"$ref":"#/components/schemas/run_flow_batch_input"},{"$ref":"#/components/schemas/get_flow_run_input"},{"$ref":"#/components/schemas/save_asset_input"},{"$ref":"#/components/schemas/list_assets_input"},{"$ref":"#/components/schemas/analyze_asset_input"},{"$ref":"#/components/schemas/create_project_input"},{"$ref":"#/components/schemas/get_project_input"},{"$ref":"#/components/schemas/list_projects_input"},{"$ref":"#/components/schemas/add_clip_input"},{"$ref":"#/components/schemas/reorder_clips_input"},{"$ref":"#/components/schemas/trim_clip_input"},{"$ref":"#/components/schemas/remove_clip_input"},{"$ref":"#/components/schemas/finalize_project_input"},{"$ref":"#/components/schemas/check_run_input"}]}}}},"responses":{"200":{"description":"The run started, completed synchronously, or needs a cost confirmation.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["runId","status","estimatedCents","checkUrl"],"properties":{"runId":{"type":"string","format":"uuid"},"status":{"type":"string","const":"running"},"estimatedCents":{"type":"integer"},"checkUrl":{"type":"string","format":"uri"},"message":{"type":"string"}}},{"type":"object","required":["status","estimatedCents","message","howToConfirm"],"properties":{"status":{"type":"string","const":"needs_confirmation"},"estimatedCents":{"type":"integer"},"message":{"type":"string"},"howToConfirm":{"type":"string"}}},{"type":"object","description":"Synchronous skill result (publish_video, check_run)."}]}}}},"400":{"description":"The input failed validation; see error.issues.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Insufficient credits, or the API key budget cap was exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Subscription or scope requirements not met.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown skill id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/uploads":{"post":{"operationId":"createUpload","summary":"Mint a signed upload URL for a local file","description":"Returns a short-lived signed URL for pushing a file into the caller's own storage. PUT the raw bytes to uploadUrl with the file content type as the Content-Type header within 2 hours, then pass the returned storagePath to a skill: save_asset for anything, create_actor for images (same path works as originalPath and processedPath), clone_voice for voice samples.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind","filename"],"properties":{"kind":{"type":"string","enum":["video","image","audio","voice"],"description":"Target bucket: video, image, audio, or voice for a voice-cloning sample."},"filename":{"type":"string","minLength":1,"maxLength":200,"description":"Original filename; used for the extension and a readable path."}}}}}},"responses":{"201":{"description":"The signed upload target.","content":{"application/json":{"schema":{"type":"object","required":["upload"],"properties":{"upload":{"type":"object","required":["kind","bucket","storagePath","uploadUrl","token"],"properties":{"kind":{"type":"string","enum":["video","image","audio","voice"]},"bucket":{"type":"string"},"storagePath":{"type":"string","description":"Pass this to the skill that takes a storagePath."},"uploadUrl":{"type":"string","format":"uri"},"token":{"type":"string"},"maxBytes":{"type":"integer"},"expiresInSeconds":{"type":"integer"},"howToUse":{"type":"string"},"createActorHint":{"type":"string","description":"Present for image uploads."}}}}}}}},"400":{"description":"Invalid kind or filename.","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":"The API requires an active Pro or Premium subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"The upload URL could not be created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/runs/{runId}":{"get":{"operationId":"getRun","summary":"Check a run and fetch its deliverable when complete","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The run status, with the deliverable once completed.","content":{"application/json":{"schema":{"type":"object","required":["runId","status"],"properties":{"runId":{"type":"string","format":"uuid"},"status":{"type":"string"},"message":{"type":"string"},"deliverable":{"type":"object","description":"Files, metadata, cost and timing of the finished run."},"error":{"type":"string"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No run with this id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/keys":{"get":{"operationId":"listApiKeys","summary":"List API keys (session auth, not key auth)","description":"Uses the logged-in web session, not an API key. Hashes are never returned.","security":[],"responses":{"200":{"description":"The API keys for the logged-in user.","content":{"application/json":{"schema":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Not logged in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createApiKey","summary":"Create an API key (session auth, not key auth)","description":"Uses the logged-in web session and requires an active Pro or Premium subscription. The plaintext key is returned exactly once.","security":[],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":80},"budgetCapCents":{"type":"integer","minimum":1,"description":"Optional per-key spending cap in credits."}}}}}},"responses":{"201":{"description":"The new key. Store the plaintext now; it is never shown again.","content":{"application/json":{"schema":{"type":"object","required":["id","name","prefix","key","message"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string"},"key":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Not logged in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API requires an active Pro or Premium subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/keys/{keyId}":{"delete":{"operationId":"revokeApiKey","summary":"Revoke an API key (session auth, not key auth)","security":[],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The key was revoked.","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"}}}}}},"401":{"description":"Not logged in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No key with this id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/flows":{"get":{"operationId":"listFlows","summary":"List your saved flows","responses":{"200":{"description":"The saved flows.","content":{"application/json":{"schema":{"type":"object","required":["flows"],"properties":{"flows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"stepCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API requires an active Pro or Premium subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createFlow","summary":"Save a flow (a validated DAG of skill steps)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowDefinition"}}}},"responses":{"201":{"description":"The flow was saved.","content":{"application/json":{"schema":{"type":"object","required":["flow","estimate"],"properties":{"flow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"stepCount":{"type":"integer"}}},"estimate":{"type":"object","properties":{"totalKnownCents":{"type":"integer"},"unknownSteps":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"description":"The definition failed validation; see error.issues.","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":"The API requires an active Pro or Premium subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/flows/{flowId}/run":{"post":{"operationId":"runFlow","summary":"Start a flow run","description":"Flows spend real credits. Without confirm: true the response is status needs_confirmation with the total estimate; repeat the call with confirm: true after the user approves. Once confirmed, every step runs pre-confirmed against the flow total, while tier budgets still apply per step.","parameters":[{"name":"flowId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Set true only after the user approved the estimated total."}}}}}},"responses":{"200":{"description":"The run started, or needs a cost confirmation.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["flowRunId","status","totalEstimatedCents","checkUrl"],"properties":{"flowRunId":{"type":"string","format":"uuid"},"status":{"type":"string"},"totalEstimatedCents":{"type":"integer"},"checkUrl":{"type":"string","format":"uri"}}},{"type":"object","required":["status","totalEstimatedCents","message","howToConfirm"],"properties":{"status":{"type":"string","const":"needs_confirmation"},"totalEstimatedCents":{"type":"integer"},"unknownSteps":{"type":"array","items":{"type":"string"}},"message":{"type":"string"},"howToConfirm":{"type":"string"}}}]}}}},"400":{"description":"The saved definition is no longer valid; see error.issues.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Insufficient credits, or the API key budget cap was exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Subscription or scope requirements not met.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No flow with this id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/flow-runs/{runId}":{"get":{"operationId":"getFlowRun","summary":"Check a flow run: per-step states and finished deliverables","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The flow run status.","content":{"application/json":{"schema":{"type":"object","required":["flowRunId","status","steps"],"properties":{"flowRunId":{"type":"string","format":"uuid"},"status":{"type":"string"},"totalEstimatedCents":{"type":"integer"},"chargedCents":{"type":"integer"},"currentSteps":{"type":"array","items":{"type":"string"}},"steps":{"type":"object","additionalProperties":{"type":"object","properties":{"status":{"type":"string"},"skillRunId":{"type":"string","format":"uuid"},"error":{"type":"string"}}}},"deliverables":{"type":"object","description":"Step id to Deliverable manifest for completed maker steps.","additionalProperties":{"type":"object"}},"error":{"type":"string"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No flow run with this id belongs to this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}