{"openapi":"3.1.0","info":{"title":"AwesomeVideo API","version":"0.3.0","summary":"Transcribe, translate, trim, clip, and burn styled captions into video.","description":"Prepaid credits, 1 credit = 1 cent. Get a key with POST /v1/keys/anonymous (no auth, 0 credits) or at https://awesomevideoeditor.com/account. Send Authorization: Bearer av_live_.... Paid calls check the balance first; when it is short they return 402 insufficient_balance with checkoutUrl (buys 500 credits for $5 for this key) and howToBuy, and nothing is charged. Failed jobs are refunded. Prices: GET /v1/pricing. Agent guide: /llms.txt. MCP: /mcp."},"servers":[{"url":"https://api.awesomevideoeditor.com"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"API key av_live_..., an OAuth access token av_oat_..., or an account session token for /v1/account routes."},"oauth2":{"type":"oauth2","description":"OAuth 2.1 authorization code with PKCE S256. Register clients dynamically at /oauth/register.","flows":{"authorizationCode":{"authorizationUrl":"https://api.awesomevideoeditor.com/oauth/authorize","tokenUrl":"https://api.awesomevideoeditor.com/oauth/token","refreshUrl":"https://api.awesomevideoeditor.com/oauth/token","scopes":{"mcp":"Use AwesomeVideo tools and spend the account balance"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Machine-readable code."},"message":{"type":"string","description":"What happened and what to do next."}},"required":["error","message"]},"LimitViolation":{"type":"object","properties":{"code":{"type":"string","description":"e.g. media_too_large, url_media_too_large, duration_too_long, shorts_count_out_of_range, transcript_too_long."},"limit":{"type":"number"},"actual":{"type":"number"},"unit":{"type":"string","enum":["bytes","seconds","clips","cues"]},"message":{"type":"string"},"hint":{"type":"string"}},"required":["code","limit","actual","unit","message","hint"]},"LimitExceeded":{"type":"object","properties":{"error":{"type":"string","enum":["limit_exceeded"]},"message":{"type":"string"},"charged":{"type":"boolean","enum":[false]},"violations":{"type":"array","items":{"$ref":"#/components/schemas/LimitViolation"}}},"required":["error","violations","charged"]},"InsufficientBalance":{"allOf":[{"type":"object","properties":{"error":{"type":"string","description":"Machine-readable code."},"message":{"type":"string","description":"What happened and what to do next."}},"required":["error","message"]},{"type":"object","properties":{"requiredCents":{"type":"number","description":"Credits the call needs."},"balanceCents":{"type":"number","description":"Credits on the key now."},"currency":{"type":"string","description":"usd"},"checkoutUrl":{"type":["string","null"],"description":"Checkout that buys 500 credits for $5 for this key. Show it to a human."},"checkoutTiedToKey":{"type":"boolean","description":"True when the checkout credits this exact key."},"howToBuy":{"type":"string","description":"Plain-language next steps."},"pricingUrl":{"type":"string","description":"Public pricing page."},"accountUrl":{"type":"string","description":"Sign-in page to claim the key and buy bigger packs or plans."}}}]},"Job":{"type":"object","properties":{"id":{"type":"string","description":"Job id."},"kind":{"type":"string","description":"transcribe, burn, preview, translate, shorts, trim, or batch."},"status":{"type":"string","description":"queued, running, succeeded, or failed."},"costCents":{"type":"number","description":"Credits charged (refunded on failure)."},"audioSeconds":{"type":"number","description":"Billed seconds."},"result":{"type":["object","null"],"description":"Outputs with expiring URLs once succeeded."},"error":{"type":["string","null"]}}},"AnonymousKey":{"type":"object","properties":{"token":{"type":"string","description":"The av_live_ key. Shown once."},"key":{"type":"object"},"balanceCents":{"type":"number","description":"Always 0."},"message":{"type":"string","description":"Next steps."}}}},"responses":{"BadRequest":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid API key. The message explains how to get one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"rate_limited. Nothing was charged. Wait Retry-After seconds (also retryAfterSeconds in the body) before retrying.","headers":{"Retry-After":{"description":"Seconds until the limit window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"rate_limited"},"message":{"type":"string","description":"What to do."},"retryAfterSeconds":{"type":"integer"},"charged":{"type":"boolean"}},"required":["error","message","retryAfterSeconds","charged"]}}}},"PaymentRequired":{"description":"insufficient_balance. Nothing was charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientBalance"}}}},"LimitExceeded":{"description":"limit_exceeded: the input is over a known limit (size, duration, clip count or length, transcript cues). Checked before any credit is reserved; charged is false. violations matches plan.limitViolations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LimitExceeded"}}}},"Conflict":{"description":"max_credits_exceeded, account_required, key_claimed, or a similar conflict.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/keys/anonymous":{"post":{"summary":"Create a self-serve API key with 0 credits. No auth. A few per network per day.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Optional label."}}}}}},"responses":{"201":{"description":"Key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnonymousKey"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/platforms":{"get":{"summary":"Platform safe zones. Free, no auth. Each: id, name, aliases, aspect, margins {top,bottom,left,right as fractions of the frame}, source. Pass id or alias as platform to burn, preview, shorts, prepare, or plan steps.","responses":{"200":{"description":"OK"}}}},"/v1/voices":{"get":{"summary":"Dub voice catalog. Free, no auth. Query: language (ISO 639-1), tier (basic|standard). Each voice: id, language, tier, provider, gender, default, creditsPerMinute, sampleUrl (MP3).","parameters":[{"name":"language","in":"query","schema":{"type":"string"}},{"name":"tier","in":"query","schema":{"type":"string","enum":["basic","standard"]}}],"responses":{"200":{"description":"OK"}}}},"/v1/pricing":{"get":{"summary":"Live prices and the operations list. No auth.","responses":{"200":{"description":"OK"}}}},"/v1/plan":{"post":{"summary":"Free, no key needed, never charges. Price an ordered pipeline (transcribe, translate, burn server|client, shorts, trim, preview, dub) and check it against the limits. Adds transcription when a later step needs it, and translation before dub unless hasTranslation. Returns steps with credits, totalCredits, totalUsd, freeAlternatives, feasible, limitViolations, limits, and with a key the balance and whether it suffices. A mediaUrl is sized with one HEAD request; the body is never downloaded. 120 calls per hour per IP.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"steps":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"object","properties":{"op":{"type":"string","enum":["transcribe","translate","burn","shorts","trim","preview","dub","style_preview"]},"renderer":{"type":"string","enum":["server","client"]},"count":{"type":"integer"},"minSeconds":{"type":"number"},"maxSeconds":{"type":"number"},"keepSeconds":{"type":"number","description":"trim: seconds you expect to keep."},"reframe":{"type":"string","enum":["face","center"],"description":"shorts: face (default) or center. Same price."},"targetLanguage":{"type":"string"},"voiceTier":{"type":"string","enum":["basic","standard"],"description":"dub only."},"voice":{"type":"string","description":"dub: voice id from GET /v1/voices."},"sourceLanguage":{"type":"string","description":"dub: spoken language, if known."}},"required":["op"]}},"source":{"type":"object","properties":{"durationSeconds":{"type":"number"},"bytes":{"type":"integer"},"via":{"type":"string","enum":["upload","url"]},"transcriptCues":{"type":"integer"},"mediaUrl":{"type":"string","format":"uri"}}},"hasTranscript":{"type":"boolean"},"hasTranslation":{"type":"boolean","description":"dub: you already have target-language lines."}},"required":["steps"]}}}},"responses":{"200":{"description":"Plan. feasible=false lists limitViolations [{code, limit, actual, unit, message, hint}]."},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/quote":{"post":{"summary":"Cents for a job before any debit. Without a key, pass operation and durationSeconds. With a key, fileId or mediaUrl are probed. Never charges.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operation":{"type":"string","enum":["caption","transcribe","burn","preview","translate","shorts","trim","dub","style_preview"]},"translateTo":{"type":"string","description":"caption only: include translation (2 credits/min) in the price."},"voiceTier":{"type":"string","enum":["basic","standard"],"description":"dub only."},"targetLanguage":{"type":"string","description":"dub only."},"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."}},"required":["operation"]}}}},"responses":{"200":{"description":"Quote"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/balance":{"get":{"security":[{"bearer":[]}],"summary":"Credits on the key, or on the account when the key is claimed.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/presets":{"get":{"security":[{"bearer":[]}],"summary":"Built-in and approved community caption presets.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/uploads":{"post":{"security":[{"bearer":[]}],"summary":"Upload media (multipart/form-data field file, up to 80 MB). Returns fileId. A JSON or other non-multipart body returns 400 multipart_form_required (nothing charged): for a PUT URL from JSON {filename, contentType, sizeBytes} use /v1/uploads/url. Larger files (up to 2048 MB): /v1/uploads/multipart.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}}}},"/v1/uploads/url":{"post":{"security":[{"bearer":[]}],"summary":"Free. Reserve a fileId and a single-use PUT URL (15 minutes) for a video or audio file. One PUT takes up to 80 MB; bigger files return 422 use_multipart_upload (use /v1/uploads/multipart, up to 2048 MB). 30 per hour.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","description":"e.g. clip.mp4"},"contentType":{"type":"string","description":"video/* or audio/*"},"sizeBytes":{"type":"number","description":"Exact size in bytes."}},"required":["filename","contentType","sizeBytes"]}}}}}},"/v1/uploads/import":{"post":{"security":[{"bearer":[]}],"summary":"Free. Download a public media link into storage and get a fileId (like /v1/uploads/url). Direct http(s) file links, chat attachment URLs, Google Drive and Dropbox share links. Up to 2048 MB when the host sends Content-Length (streamed to storage), 80 MB otherwise (422 limit_exceeded, charged:false). YouTube/TikTok/Instagram return 422 youtube_not_supported / platform_url_unsupported: upload the file instead. Private, loopback, link-local, metadata, and non-default-port targets are blocked; every redirect is re-checked. 30 per hour.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Public link to the video or audio file.","format":"uri"},"filename":{"type":"string","description":"Optional name."}},"required":["url"]}}}}}},"/v1/uploads/{fileId}":{"put":{"security":[],"summary":"Send the raw file bytes to the uploadUrl from /v1/uploads/url (token in the query string, no API key). Content-Length must equal sizeBytes. Single use.","parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Stored. Returns fileId and bytes."},"400":{"description":"size_mismatch"},"403":{"description":"invalid_upload_url"},"409":{"description":"upload_url_used"},"410":{"description":"upload_url_expired"}}},"get":{"security":[{"bearer":[]},{}],"summary":"Free. Multipart upload status, for resuming: state (uploading|completed|aborted), completedParts, missingParts, bytesReceived, and (with token) missing[] with each missing part's offset, length, and PUT url.","parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":false,"schema":{"type":"string"},"description":"uploadToken from /v1/uploads/multipart (already in its URLs). Without it, send the API key that created the upload."}],"responses":{"200":{"description":"Status"},"403":{"description":"invalid_upload_url"},"404":{"description":"upload_not_found"},"410":{"description":"upload_expired (24 h)"}}},"delete":{"security":[{"bearer":[]},{}],"summary":"Free. Abort an unfinished multipart upload and drop its parts.","parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":false,"schema":{"type":"string"},"description":"uploadToken from /v1/uploads/multipart (already in its URLs). Without it, send the API key that created the upload."}],"responses":{"200":{"description":"state: aborted"},"409":{"description":"upload_completed"}}}},"/v1/uploads/multipart":{"post":{"security":[{"bearer":[]}],"summary":"Free. Resumable upload for files up to 2048 MB (and any upload on a flaky link). Returns fileId, uploadToken, partSizeBytes (default 64 MB, 5-95 MB), partCount, parts[] {partNumber, offset, length, url}, statusUrl, completeUrl, abortUrl; valid 24 h. PUT bytes [offset, offset+length) to each part url (no API key; any order, parallel OK, re-sending replaces). If interrupted, GET statusUrl and send only missingParts. Then POST completeUrl. Example: for each part, tail -c +$((offset+1)) talk.mp4 | head -c $length | curl -X PUT --data-binary @- -H \"Content-Length: $length\" \"$url\". 30 per hour.","responses":{"201":{"description":"Upload created"},"422":{"description":"limit_exceeded (over 2048 MB) or invalid input; charged:false"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","description":"e.g. talk.mp4"},"contentType":{"type":"string","description":"video/* or audio/*"},"sizeBytes":{"type":"number","description":"Exact size in bytes (up to 2147483648)."},"partSizeBytes":{"type":"number","description":"Bytes per part, 5242880-99614720. Default 67108864."}},"required":["filename","contentType","sizeBytes"]}}}}}},"/v1/uploads/{fileId}/parts/{partNumber}":{"put":{"security":[],"summary":"Send one part (the url from parts[] carries the token). Content-Length must equal that part's length. Re-sending a part replaces it.","parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}},{"name":"partNumber","in":"path","required":true,"schema":{"type":"integer","minimum":1}},{"name":"token","in":"query","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Stored: partNumber, bytes, etag"},"400":{"description":"size_mismatch / invalid_part_number"},"403":{"description":"invalid_upload_url"},"409":{"description":"upload_completed / upload_aborted"},"500":{"description":"upload_failed: PUT the same part again"}}}},"/v1/uploads/{fileId}/complete":{"post":{"security":[{"bearer":[]},{}],"summary":"Free. Assemble the parts into the file; idempotent. 409 upload_incomplete lists missingParts. Then pass fileId to any tool.","parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"query","required":false,"schema":{"type":"string"},"description":"uploadToken from /v1/uploads/multipart (already in its URLs). Without it, send the API key that created the upload."}],"responses":{"200":{"description":"fileId, bytes, contentType, state: completed"},"409":{"description":"upload_incomplete (missingParts) or upload_aborted"}}}},"/v1/captions":{"post":{"security":[{"bearer":[]}],"summary":"One call: transcribe -> optional translate -> burn. Prefer this for 'burn subtitles into this video'. Priced as the sum of the steps, no surcharge: 5 credits per audio minute (1 transcribe + 4 burn), +2 with translateTo. Returns the MP4, SRT, VTT, JSON links, the transcript, and creditsCharged. Pass wait:true (or waitSeconds up to 50) to block until done; otherwise 202 with a job id to poll at /v1/jobs/{id}. Every job view has step, steps, stepProgress, progress (0-100), eta_seconds, estimatedCompletionAt, and pollAfterSeconds. Failed jobs refund automatically and, when they failed after transcribing, can resume at /v1/jobs/{id}/resume paying only the remaining steps; over-limit input fails with 422 and charged:false.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceUrl":{"type":"string","description":"Public link: direct file, chat attachment, Google Drive or Dropbox share link. Not YouTube.","format":"uri"},"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"language":{"type":"string","description":"Spoken language (BCP-47) or omit for auto."},"translateTo":{"type":"string","description":"ISO 639-1 language to translate the burned captions to."},"preset":{"type":"string","description":"Preset id or name from GET /v1/presets, e.g. Clarity."},"brandPresetId":{"type":"string","description":"Saved brand preset id."},"styleOverrides":{"type":"object","additionalProperties":true,"description":"Per-call style fields deep-merged onto the preset (null removes), validated like custom presets (bundled fonts only). Example {\"fontSize\":72,\"maxWordsPerCaption\":2,\"faceAvoid\":true}. Same price."},"faceAvoid":{"type":"boolean","description":"true = keep captions off faces (2 fps face sampling, same price). Shortcut for styleOverrides.faceAvoid."},"platform":{"type":"string","description":"tiktok, reels, shorts, youtube, or none."},"glossary":{"type":"array","items":{"type":"string"},"description":"Names and brand terms."},"audioVisual":{"type":"object","additionalProperties":false,"description":"Audio-only input (mp3, m4a, wav...): an editorial podcast design plus captions, drawn on the server by the web editor's own code, same price as the burn. {variant: swiss-grid | braun-radio | riso | editorial-cover | bauhaus | continuous-line | vinyl | type-wave | duotone-portrait | ma (default editorial-cover), showName (<=60), episode (<=12), speaker (<=60), coverImageUrl (https) or coverFileId (PNG/JPEG/WebP <=5 MB; shown by vinyl, duotone-portrait), background/accent/ink (#hex; ink auto from paper), captionMode integrated (default: the design typesets the captions) | preset (your caption preset draws), contrastGuard (default true), aspect 9:16|16:9|1:1|4:5 or width+height, overlays (<=8)}. Retired ids still work as aliases with a warning: bars→swiss-grid, ribbon→continuous-line, rings→ma, spectrogram→riso, skyline→bauhaus, silkline→type-wave, ivory→editorial-cover, halo→vinyl, needle→braun-radio, mono→duotone-portrait. On a video input: 422 audio_visual_needs_audio_input, not charged. Catalog: GET /v1/audio-visuals (MCP list_audio_visuals), free.","properties":{"variant":{"type":"string","enum":["swiss-grid","braun-radio","riso","editorial-cover","bauhaus","continuous-line","vinyl","type-wave","duotone-portrait","ma","bars","ribbon","rings","spectrogram","skyline","silkline","ivory","halo","needle","mono"],"default":"editorial-cover","description":"Design id. swiss-grid: Swiss grid; braun-radio: Braun radio; riso: Riso print; editorial-cover: Editorial cover; bauhaus: Bauhaus; continuous-line: Continuous line; vinyl: Vinyl; type-wave: Type as waveform; duotone-portrait: Duotone portrait; ma: Ma. Deprecated aliases (render their replacement, response carries warnings): bars→swiss-grid, ribbon→continuous-line, rings→ma, spectrogram→riso, skyline→bauhaus, silkline→type-wave, ivory→editorial-cover, halo→vinyl, needle→braun-radio, mono→duotone-portrait."},"enabled":{"type":"boolean","default":true,"description":"false: paper colour + captions only."},"showName":{"type":"string","maxLength":60,"description":"Show / podcast name. Used in mastheads, labels and seals. Empty: the element is omitted (masthead designs fall back to \"Podcast\")."},"episode":{"oneOf":[{"type":"string","maxLength":12},{"type":"number"}],"description":"Episode label or number, e.g. \"42\" or \"S2·E7\". Printed after Nº. Empty: omitted (Swiss grid shows the running timecode as its numeral)."},"speaker":{"type":"string","maxLength":60,"description":"Speaker / host name for bylines and name plates. Empty: omitted."},"coverImageUrl":{"type":"string","format":"uri","maxLength":2000,"description":"Public https URL of a PNG/JPEG/WebP (max 5 MB), fetched before any charge. Optional cover art or host photo (PNG/JPEG/WebP, max 5 MB). Used by designs that list it in `usesCover`; ignored by the others. Empty: the design draws its own graphic."},"coverFileId":{"type":"string","description":"fileId of an uploaded PNG/JPEG/WebP (max 5 MB), instead of coverImageUrl."},"background":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Paper (ground) colour, #rgb or #rrggbb. Default: the design's own paper. Text ink is picked automatically for contrast unless `ink` is set."},"accent":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Accent colour (#hex): the spoken word, needles, seals, rules. Default: the design's own accent."},"ink":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Text/line colour (#hex). Default: the design's ink, or near-black/near-white chosen from the paper's luminance when `background` is changed."},"captionMode":{"type":"string","enum":["integrated","preset"],"default":"integrated","description":"integrated: the design typesets the transcript itself (pull-quote, word by word) and the caption preset is not drawn. preset: your caption preset draws as usual and the design keeps its caption band clear."},"contrastGuard":{"type":"boolean","default":true,"description":"preset mode only: when the preset's text colour has too little contrast with the paper (e.g. white text on a light design), the caption text switches to the design's ink and drops its stroke/shadow."},"aspect":{"type":"string","enum":["9:16","16:9","1:1","4:5"],"default":"9:16","description":"Frame shape; default from platform, else 9:16."},"width":{"type":"integer","minimum":128,"maximum":3840,"description":"With height: explicit frame size (long edge capped like the burn)."},"height":{"type":"integer","minimum":128,"maximum":3840},"overlays":{"type":"array","maxItems":8,"items":{"type":"object","additionalProperties":true},"description":"Up to 8 image (imageUrl/fileId, PNG/JPEG/WebP <=5 MB) or text items {kind, x, y, width, height, start, end, rotation, opacity, borderRadius, zIndex, style}."},"presetId":{"type":"string","deprecated":true,"description":"Retired (old bars presets): ignored with a warning."},"config":{"type":"object","deprecated":true,"additionalProperties":true,"description":"Retired (old visualizer config): ignored with a warning."}}},"review":{"type":"boolean","description":"Human review link before burning (when available)."},"wait":{"type":"boolean","description":"Block until done, up to waitSeconds (default 45)."},"waitSeconds":{"type":"number","description":"0-50.","minimum":0,"maximum":50},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/transcribe":{"post":{"security":[{"bearer":[]}],"summary":"Transcribe speech. 1 credit per audio minute.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"language":{"type":"string","description":"BCP-47 code or omit for auto."},"format":{"type":"string","enum":["srt","vtt","json"]},"glossary":{"type":"array","items":{"type":"string"},"description":"Names and terms. Included."},"useSavedGlossary":{"type":"boolean","description":"Default true: also apply the saved glossary (/v1/glossary)."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/captions/burn":{"post":{"security":[{"bearer":[]}],"summary":"Burn styled captions into the video. 4 credits per audio minute.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"subtitles":{"type":"string","description":"SRT, VTT, or JSON cues."},"transcriptionJobId":{"type":"string","description":"Id of a finished transcription job on this key."},"preset":{"type":"string","description":"Preset id or name from GET /v1/presets, e.g. Clarity."},"brandPresetId":{"type":"string","description":"Saved brand preset id."},"styleOverrides":{"type":"object","additionalProperties":true,"description":"Per-call style fields deep-merged onto the preset (null removes), validated like custom presets (bundled fonts only). Example {\"fontSize\":72,\"maxWordsPerCaption\":2,\"faceAvoid\":true}. Same price."},"faceAvoid":{"type":"boolean","description":"true = keep captions off faces (2 fps face sampling, same price). Shortcut for styleOverrides.faceAvoid."},"platform":{"type":"string","description":"Where the video will be posted: tiktok, instagram_reels, youtube_shorts, facebook_reels, snapchat_spotlight, linkedin, youtube, x, or an alias (reels, instagram, shorts, snap, twitter). Case-insensitive. Keeps captions inside that app's safe zone; style unchanged, same price. Unknown: 422 invalid_platform. See GET /v1/platforms."},"autoFit":{"type":"boolean","description":"Default true: caption size, words per caption (4 on 9:16, 5 on 1:1, 7 on 16:9), and a default safe zone follow the video shape. false = the preset's fixed pixel sizes. Same price."},"combined":{"type":"boolean","description":"Also return SRT, VTT, and JSON at the burn price."},"audioVisual":{"type":"object","additionalProperties":false,"description":"Audio-only input (mp3, m4a, wav...): an editorial podcast design plus captions, drawn on the server by the web editor's own code, same price as the burn. {variant: swiss-grid | braun-radio | riso | editorial-cover | bauhaus | continuous-line | vinyl | type-wave | duotone-portrait | ma (default editorial-cover), showName (<=60), episode (<=12), speaker (<=60), coverImageUrl (https) or coverFileId (PNG/JPEG/WebP <=5 MB; shown by vinyl, duotone-portrait), background/accent/ink (#hex; ink auto from paper), captionMode integrated (default: the design typesets the captions) | preset (your caption preset draws), contrastGuard (default true), aspect 9:16|16:9|1:1|4:5 or width+height, overlays (<=8)}. Retired ids still work as aliases with a warning: bars→swiss-grid, ribbon→continuous-line, rings→ma, spectrogram→riso, skyline→bauhaus, silkline→type-wave, ivory→editorial-cover, halo→vinyl, needle→braun-radio, mono→duotone-portrait. On a video input: 422 audio_visual_needs_audio_input, not charged. Catalog: GET /v1/audio-visuals (MCP list_audio_visuals), free.","properties":{"variant":{"type":"string","enum":["swiss-grid","braun-radio","riso","editorial-cover","bauhaus","continuous-line","vinyl","type-wave","duotone-portrait","ma","bars","ribbon","rings","spectrogram","skyline","silkline","ivory","halo","needle","mono"],"default":"editorial-cover","description":"Design id. swiss-grid: Swiss grid; braun-radio: Braun radio; riso: Riso print; editorial-cover: Editorial cover; bauhaus: Bauhaus; continuous-line: Continuous line; vinyl: Vinyl; type-wave: Type as waveform; duotone-portrait: Duotone portrait; ma: Ma. Deprecated aliases (render their replacement, response carries warnings): bars→swiss-grid, ribbon→continuous-line, rings→ma, spectrogram→riso, skyline→bauhaus, silkline→type-wave, ivory→editorial-cover, halo→vinyl, needle→braun-radio, mono→duotone-portrait."},"enabled":{"type":"boolean","default":true,"description":"false: paper colour + captions only."},"showName":{"type":"string","maxLength":60,"description":"Show / podcast name. Used in mastheads, labels and seals. Empty: the element is omitted (masthead designs fall back to \"Podcast\")."},"episode":{"oneOf":[{"type":"string","maxLength":12},{"type":"number"}],"description":"Episode label or number, e.g. \"42\" or \"S2·E7\". Printed after Nº. Empty: omitted (Swiss grid shows the running timecode as its numeral)."},"speaker":{"type":"string","maxLength":60,"description":"Speaker / host name for bylines and name plates. Empty: omitted."},"coverImageUrl":{"type":"string","format":"uri","maxLength":2000,"description":"Public https URL of a PNG/JPEG/WebP (max 5 MB), fetched before any charge. Optional cover art or host photo (PNG/JPEG/WebP, max 5 MB). Used by designs that list it in `usesCover`; ignored by the others. Empty: the design draws its own graphic."},"coverFileId":{"type":"string","description":"fileId of an uploaded PNG/JPEG/WebP (max 5 MB), instead of coverImageUrl."},"background":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Paper (ground) colour, #rgb or #rrggbb. Default: the design's own paper. Text ink is picked automatically for contrast unless `ink` is set."},"accent":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Accent colour (#hex): the spoken word, needles, seals, rules. Default: the design's own accent."},"ink":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Text/line colour (#hex). Default: the design's ink, or near-black/near-white chosen from the paper's luminance when `background` is changed."},"captionMode":{"type":"string","enum":["integrated","preset"],"default":"integrated","description":"integrated: the design typesets the transcript itself (pull-quote, word by word) and the caption preset is not drawn. preset: your caption preset draws as usual and the design keeps its caption band clear."},"contrastGuard":{"type":"boolean","default":true,"description":"preset mode only: when the preset's text colour has too little contrast with the paper (e.g. white text on a light design), the caption text switches to the design's ink and drops its stroke/shadow."},"aspect":{"type":"string","enum":["9:16","16:9","1:1","4:5"],"default":"9:16","description":"Frame shape; default from platform, else 9:16."},"width":{"type":"integer","minimum":128,"maximum":3840,"description":"With height: explicit frame size (long edge capped like the burn)."},"height":{"type":"integer","minimum":128,"maximum":3840},"overlays":{"type":"array","maxItems":8,"items":{"type":"object","additionalProperties":true},"description":"Up to 8 image (imageUrl/fileId, PNG/JPEG/WebP <=5 MB) or text items {kind, x, y, width, height, start, end, rotation, opacity, borderRadius, zIndex, style}."},"presetId":{"type":"string","deprecated":true,"description":"Retired (old bars presets): ignored with a warning."},"config":{"type":"object","deprecated":true,"additionalProperties":true,"description":"Retired (old visualizer config): ignored with a warning."}}},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/captions/preview":{"post":{"security":[{"bearer":[]}],"summary":"One PNG frame (at atSeconds, default 0) or a clip of at most 5 s with a preset. 1 credit flat. Misnamed fields such as at, time, seconds, or presets return 400 unknown_field with the right name, before any charge. For several presets on several seconds use the free /v1/captions/style-preview.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"subtitles":{"type":"string","description":"SRT, VTT, or JSON cues."},"transcriptionJobId":{"type":"string","description":"Id of a finished transcription job on this key."},"preset":{"type":"string","description":"Preset id or name from GET /v1/presets, e.g. Clarity."},"brandPresetId":{"type":"string","description":"Saved brand preset id."},"styleOverrides":{"type":"object","additionalProperties":true,"description":"Per-call style fields deep-merged onto the preset (null removes), validated like custom presets (bundled fonts only). Example {\"fontSize\":72,\"maxWordsPerCaption\":2,\"faceAvoid\":true}. Same price."},"faceAvoid":{"type":"boolean","description":"true = keep captions off faces (2 fps face sampling, same price). Shortcut for styleOverrides.faceAvoid."},"platform":{"type":"string","description":"Where the video will be posted: tiktok, instagram_reels, youtube_shorts, facebook_reels, snapchat_spotlight, linkedin, youtube, x, or an alias (reels, instagram, shorts, snap, twitter). Case-insensitive. Keeps captions inside that app's safe zone; style unchanged, same price. Unknown: 422 invalid_platform. See GET /v1/platforms."},"autoFit":{"type":"boolean","description":"Default true: caption size, words per caption (4 on 9:16, 5 on 1:1, 7 on 16:9), and a default safe zone follow the video shape. false = the preset's fixed pixel sizes. Same price."},"mode":{"type":"string","enum":["still","clip"]},"atSeconds":{"type":"number","description":"Frame or clip start."},"clipSeconds":{"type":"number","description":"Clip length, at most 5.","maximum":5},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/translate":{"post":{"security":[{"bearer":[]}],"summary":"Translate captions and keep cue timing. 2 credits per minute; burn:true adds the burn price. Word-level highlight is not kept.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subtitles":{"type":"string","description":"SRT, VTT, or JSON cues."},"transcriptionJobId":{"type":"string","description":"Id of a finished transcription job on this key."},"targetLanguage":{"type":"string","description":"ISO 639-1 code, e.g. es, fr, de, pt, ja. Unsupported codes return 400."},"sourceLanguage":{"type":"string","description":"ISO 639-1. Defaults to the transcript language."},"burn":{"type":"boolean","description":"Also burn the translated captions (needs media)."},"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"preset":{"type":"string","description":"Preset id or name from GET /v1/presets, e.g. Clarity."},"brandPresetId":{"type":"string","description":"Saved brand preset id."},"styleOverrides":{"type":"object","additionalProperties":true,"description":"Per-call style fields deep-merged onto the preset (null removes), validated like custom presets (bundled fonts only). Example {\"fontSize\":72,\"maxWordsPerCaption\":2,\"faceAvoid\":true}. Same price."},"faceAvoid":{"type":"boolean","description":"true = keep captions off faces (2 fps face sampling, same price). Shortcut for styleOverrides.faceAvoid."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}},"required":["targetLanguage"]}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/shorts":{"post":{"security":[{"bearer":[]}],"summary":"Pick moments, reframe to 720x1280 (face tracking by default, center crop fallback), and burn captions. 6 credits per source minute.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"subtitles":{"type":"string","description":"SRT, VTT, or JSON cues."},"transcriptionJobId":{"type":"string","description":"Id of a finished transcription job on this key."},"preset":{"type":"string","description":"Preset id or name from GET /v1/presets, e.g. Clarity."},"brandPresetId":{"type":"string","description":"Saved brand preset id."},"styleOverrides":{"type":"object","additionalProperties":true,"description":"Per-call style fields deep-merged onto the preset (null removes), validated like custom presets (bundled fonts only). Example {\"fontSize\":72,\"maxWordsPerCaption\":2,\"faceAvoid\":true}. Same price."},"faceAvoid":{"type":"boolean","description":"true = keep captions off faces (2 fps face sampling, same price). Shortcut for styleOverrides.faceAvoid."},"platform":{"type":"string","description":"Where the video will be posted: tiktok, instagram_reels, youtube_shorts, facebook_reels, snapchat_spotlight, linkedin, youtube, x, or an alias (reels, instagram, shorts, snap, twitter). Case-insensitive. Keeps captions inside that app's safe zone; style unchanged, same price. Unknown: 422 invalid_platform. See GET /v1/platforms."},"autoFit":{"type":"boolean","description":"Default true: caption size, words per caption (4 on 9:16, 5 on 1:1, 7 on 16:9), and a default safe zone follow the video shape. false = the preset's fixed pixel sizes. Same price."},"count":{"type":"integer","minimum":1,"maximum":5},"minSeconds":{"type":"number","description":"Clip minimum length.","minimum":5,"maximum":60},"maxSeconds":{"type":"number","description":"Clip maximum length.","minimum":5,"maximum":60},"reframe":{"type":"string","enum":["face","center"],"default":"face","description":"face tracks the main speaker and falls back to center when no face is found; center forces a center crop. Same price."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/clips":{"post":{"security":[{"bearer":[]}],"summary":"Long video to short clips in one call: transcribe (or reuse transcriptionJobId/subtitles), an LLM picks count self-contained moments snapped to sentence boundaries, each rendered as MP4 (9:16 face-tracked (default) or center crop or source shape) with optional burned captions. Returns clips with title, hook, reason, score, start/end and URLs. Price: 1 credit/source min (transcribe, 0 with a transcript) + 1 per started 10 source min + 3 per output min (reserved for count x maxSeconds; unused part refunded). quoteOnly:true with durationSeconds prices it without a job.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceUrl":{"type":"string","description":"Public https link. YouTube, TikTok and Instagram links return 422."},"fileId":{"type":"string","description":"From POST /v1/uploads/url, /v1/uploads/import, or /v1/uploads."},"subtitles":{"type":"string","description":"SRT, VTT, or JSON cues."},"transcriptionJobId":{"type":"string","description":"Id of a finished transcription job on this key."},"preset":{"type":"string","description":"Preset id or name from GET /v1/presets, e.g. Clarity."},"brandPresetId":{"type":"string","description":"Saved brand preset id."},"styleOverrides":{"type":"object","additionalProperties":true,"description":"Per-call style fields deep-merged onto the preset (null removes), validated like custom presets (bundled fonts only). Example {\"fontSize\":72,\"maxWordsPerCaption\":2,\"faceAvoid\":true}. Same price."},"faceAvoid":{"type":"boolean","description":"true = keep captions off faces (2 fps face sampling, same price). Shortcut for styleOverrides.faceAvoid."},"platform":{"type":"string","description":"Where the video will be posted: tiktok, instagram_reels, youtube_shorts, facebook_reels, snapchat_spotlight, linkedin, youtube, x, or an alias (reels, instagram, shorts, snap, twitter). Case-insensitive. Keeps captions inside that app's safe zone; style unchanged, same price. Unknown: 422 invalid_platform. See GET /v1/platforms."},"autoFit":{"type":"boolean","description":"Default true: caption size, words per caption (4 on 9:16, 5 on 1:1, 7 on 16:9), and a default safe zone follow the video shape. false = the preset's fixed pixel sizes. Same price."},"language":{"type":"string","description":"Spoken language. Omit for auto."},"count":{"type":"integer","minimum":1,"maximum":10,"default":3},"minSeconds":{"type":"number","description":"Shortest clip.","minimum":5,"maximum":90},"maxSeconds":{"type":"number","description":"Longest clip.","minimum":5,"maximum":90},"reframe":{"type":"string","enum":["face","center","none"],"default":"face"},"captions":{"type":"boolean","description":"Burn captions. Default true."},"quoteOnly":{"type":"boolean","description":"Price only, needs durationSeconds."},"wait":{"type":"boolean","description":"Block up to waitSeconds (max 50)."},"waitSeconds":{"type":"number","description":"Default 45 with wait:true."},"durationSeconds":{"type":"number","description":"Source duration hint."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/dub":{"post":{"security":[{"bearer":[]}],"summary":"Dub the video into targetLanguage. Voice 5 credits per source minute (basic: en, es, fr, zh, ja, ko, hi, ar, bn, pt, ru, ur, id, de, tr, it, vi) or 12 (standard: en, es, hi, ar, bn, pt, ru, ur, id, de, tr, it, vi), plus transcription 1/min and translation 2/min when not reused. Lines are fitted to the original timing (up to 1.25x, one shorter rewrite, silence padding) and mixed over the original audio ducked to -18 dB or muted. Unsupported languages return 422 before any charge.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"subtitles":{"type":"string","description":"SRT, VTT, or JSON cues."},"transcriptionJobId":{"type":"string","description":"Id of a finished transcription job on this key."},"targetLanguage":{"type":"string","description":"ISO 639-1: en, es, fr, zh, ja, ko, hi, ar, bn, pt, ru, ur, id, de, tr, it, vi."},"sourceLanguage":{"type":"string","description":"Spoken language, if known."},"translationJobId":{"type":"string","description":"A finished translate job into targetLanguage."},"translatedSubtitles":{"type":"string","description":"Target-language SRT, VTT, or JSON."},"voiceTier":{"type":"string","enum":["basic","standard"]},"voice":{"type":"string","description":"Voice id from GET /v1/voices (validated: 422 before charging if unknown or the wrong language or tier). Omit for the default."},"keepOriginalAudio":{"type":"string","enum":["duck","mute"]},"audioTrack":{"type":"boolean","description":"Also return the dubbed audio as M4A."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}},"required":["targetLanguage"]}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/metadata":{"post":{"security":[{"bearer":[]}],"summary":"Titles, description, hashtags, and YouTube chapters from what is said. 1 credit per platform from an existing transcript (never re-transcribes); transcription (1 credit/min) is added when only media is passed. Result platforms.<platform> = {titles, description, hashtags, chapters, descriptionWithChapters}.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Source length for quoteOnly."},"subtitles":{"type":"string","description":"SRT, VTT, or JSON cues."},"transcriptionJobId":{"type":"string","description":"Id of a finished transcription job on this key."},"jobId":{"type":"string","description":"Alias of transcriptionJobId: any finished job with captions."},"quoteOnly":{"type":"boolean","description":"Free: price only, no job, never charges. Media-only needs durationSeconds."},"platforms":{"type":"array","items":{"type":"string","enum":["youtube","shorts","tiktok","instagram"]},"description":"Default [youtube]. 1 credit each."},"language":{"type":"string","description":"Output language. Default: the video's language."},"titleCount":{"type":"integer","minimum":1,"maximum":10,"default":5},"context":{"type":"string","description":"Creator notes, up to 500 characters."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/trim":{"post":{"security":[{"bearer":[]}],"summary":"Remove silences and filler words (MCP remove_silences / trim), retime captions, optionally burn them in the same job. 3 credits per kept minute, +4 per kept minute with burnCaptions. Result has stats {sourceSeconds, keptSeconds, removedSeconds, cuts, fillersRemoved}.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string"},"fileId":{"type":"string"},"subtitles":{"type":"string","description":"SRT, VTT, or transcript JSON."},"transcriptionJobId":{"type":"string"},"silenceGapSeconds":{"type":"number","minimum":0.2,"maximum":3,"default":0.5,"description":"Pauses longer than this are cut."},"paddingSeconds":{"type":"number","minimum":0,"maximum":0.3,"default":0.08,"description":"Kept on each side of a cut."},"detectSilences":{"type":"boolean","default":true,"description":"ffmpeg silencedetect also cuts long pauses inside word timings."},"silenceNoiseDb":{"type":"number","minimum":-80,"maximum":-10,"default":-35},"removeFillers":{"type":"boolean","default":true},"fillerMode":{"type":"string","enum":["clear","aggressive"],"default":"clear"},"fillers":{"type":"array","items":{"type":"string"},"description":"Extra fillers (words or phrases) to always cut."},"keepFillers":{"type":"array","items":{"type":"string"},"description":"Fillers to keep."},"burnCaptions":{"type":"boolean","description":"Burn the retimed captions in the same job."},"quoteOnly":{"type":"boolean","description":"Free: price for durationSeconds (upper bound, every second kept); no job, never charges."},"durationSeconds":{"type":"number","description":"Source length for quoteOnly."},"preset":{"type":"string"},"brandPresetId":{"type":"string"},"styleOverrides":{"type":"object","additionalProperties":true},"faceAvoid":{"type":"boolean"},"platform":{"type":"string"},"autoFit":{"type":"boolean"},"maxCredits":{"type":"number"},"webhookUrl":{"type":"string"},"notifyEmail":{"type":"string"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/captions/trim":{"post":{"security":[{"bearer":[]}],"summary":"Remove silences and filler words (MCP remove_silences / trim), retime captions, optionally burn them in the same job. 3 credits per kept minute, +4 per kept minute with burnCaptions. Result has stats {sourceSeconds, keptSeconds, removedSeconds, cuts, fillersRemoved}.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string"},"fileId":{"type":"string"},"subtitles":{"type":"string","description":"SRT, VTT, or transcript JSON."},"transcriptionJobId":{"type":"string"},"silenceGapSeconds":{"type":"number","minimum":0.2,"maximum":3,"default":0.5,"description":"Pauses longer than this are cut."},"paddingSeconds":{"type":"number","minimum":0,"maximum":0.3,"default":0.08,"description":"Kept on each side of a cut."},"detectSilences":{"type":"boolean","default":true,"description":"ffmpeg silencedetect also cuts long pauses inside word timings."},"silenceNoiseDb":{"type":"number","minimum":-80,"maximum":-10,"default":-35},"removeFillers":{"type":"boolean","default":true},"fillerMode":{"type":"string","enum":["clear","aggressive"],"default":"clear"},"fillers":{"type":"array","items":{"type":"string"},"description":"Extra fillers (words or phrases) to always cut."},"keepFillers":{"type":"array","items":{"type":"string"},"description":"Fillers to keep."},"burnCaptions":{"type":"boolean","description":"Burn the retimed captions in the same job."},"quoteOnly":{"type":"boolean","description":"Free: price for durationSeconds (upper bound, every second kept); no job, never charges."},"durationSeconds":{"type":"number","description":"Source length for quoteOnly."},"preset":{"type":"string"},"brandPresetId":{"type":"string"},"styleOverrides":{"type":"object","additionalProperties":true},"faceAvoid":{"type":"boolean"},"platform":{"type":"string"},"autoFit":{"type":"boolean"},"maxCredits":{"type":"number"},"webhookUrl":{"type":"string"},"notifyEmail":{"type":"string"}}}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/batch":{"post":{"security":[{"bearer":[]}],"summary":"Up to 10 transcribe or burn items in one call. dryRun returns the total without charging.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operation":{"type":"string","enum":["transcribe","burn"]},"items":{"type":"array","maxItems":10,"items":{"type":"object"}},"preset":{"type":"string","description":"Default preset for burn items."},"dryRun":{"type":"boolean","description":"Quote only."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}},"required":["operation","items"]}}}},"responses":{"202":{"description":"Job accepted. Poll GET /v1/jobs/{id}.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/LimitExceeded"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/reviews":{"post":{"summary":"Free. Human review link for a finished transcription. Returns reviewUrl (web editor, no login, up to 7 days). The burn runs and is charged only when the reviewer approves. webhookUrl/notifyEmail get review.approved, review.rejected (note) and review.expired once each (signed like job webhooks; expiry is detected on the next read).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transcriptionJobId":{"type":"string","description":"Succeeded transcribe job."},"preset":{"type":"string","description":"Preset id or name from GET /v1/presets, e.g. Clarity."},"brandPresetId":{"type":"string","description":"Saved brand preset id."},"styleOverrides":{"type":"object","additionalProperties":true,"description":"Per-call style fields deep-merged onto the preset (null removes), validated like custom presets (bundled fonts only). Example {\"fontSize\":72,\"maxWordsPerCaption\":2,\"faceAvoid\":true}. Same price."},"faceAvoid":{"type":"boolean","description":"true = keep captions off faces (2 fps face sampling, same price). Shortcut for styleOverrides.faceAvoid."},"platform":{"type":"string","description":"Safe-zone platform for the burn."},"instructions":{"type":"string","description":"Shown to the reviewer."},"expiresInDays":{"type":"number","description":"1-7, default 7."},"combined":{"type":"boolean","description":"Also return SRT/VTT."},"maxCredits":{"type":"number","description":"Refuse the job (409 max_credits_exceeded) when it would cost more than this many credits. Nothing is charged.","minimum":0},"webhookUrl":{"type":"string","description":"Public https URL. Receives a signed POST when the job finishes. Works on any key.","format":"uri"},"notifyEmail":{"type":"string","description":"Optional completion email. Free.","format":"email"}},"required":["transcriptionJobId"]}}}},"responses":{"201":{"description":"reviewId, reviewUrl, status awaiting_review, estimatedBurnCredits, charged false."},"410":{"description":"media_expired"}}}},"/v1/reviews/{id}":{"get":{"security":[{"bearer":[]}],"summary":"Review status: awaiting_review, approved (burnJobId, burnJob), rejected (note), expired.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/glossary":{"get":{"summary":"Free. Saved glossary entries {term, aliases, doNotTranslate, note}.","responses":{"200":{"description":"entries"}}},"post":{"summary":"Free. Merge entries by term (mode replace swaps the list). Applied to every transcribe and translate.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","maxItems":200,"items":{"type":"object","properties":{"term":{"type":"string","description":"Correct spelling."},"aliases":{"type":"array","maxItems":10,"items":{"type":"string"},"description":"What speech-to-text writes instead."},"doNotTranslate":{"type":"boolean","description":"Keep as is in translations."},"note":{"type":"string","description":"Optional."}},"required":["term"]}},"mode":{"type":"string","enum":["merge","replace"]}},"required":["entries"]}}}},"responses":{"200":{"description":"entries"}}},"delete":{"summary":"Free. Body {terms:[...]} or {all:true}.","responses":{"200":{"description":"entries"}}}},"/v1/batches/{id}":{"get":{"security":[{"bearer":[]}],"summary":"Batch status and child jobs.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/jobs":{"get":{"security":[{"bearer":[]}],"summary":"Recent jobs with download links while results exist. Failed jobs also carry error and resumable (true: POST /v1/jobs/{id}/resume continues it; the web account page shows a Resume button for these).","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/jobs/{id}":{"get":{"security":[{"bearer":[]}],"summary":"Job status, step, progress (0-100), stepProgress, eta_seconds, estimatedCompletionAt, pollAfterSeconds, failedStep/resumable on failures, and result URLs.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"security":[{"bearer":[]}],"summary":"Replace cues on a finished transcription. Free. The next burn pays only the burn.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cues":{"type":"array","items":{"type":"object"}},"subtitles":{"type":"string","description":"SRT, VTT, or JSON."}}}}}}}},"/v1/jobs/{id}/resume":{"post":{"summary":"Resume a failed caption, transcribe, clips, dub, trim or metadata job from where it stopped. Transcription chunks the failed attempt finished are reused; the price is the original minus the transcription minutes already done (caption jobs with a finished transcript pay only the remaining steps, usually burn at 4 credits/min). The failed job stays refunded. Idempotent (no double charge). Alias: /v1/jobs/{id}/retry. Example: curl -X POST -H 'authorization: Bearer $KEY' .../v1/jobs/JOB_ID/resume. 422 resume_unavailable / resume_not_supported / resume_media_expired with charged:false.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"maxCredits":{"type":"number"},"webhookUrl":{"type":"string"},"notifyEmail":{"type":"string"}}}}}},"responses":{"202":{"description":"Resumed job (poll /v1/jobs/{id})."},"404":{"description":"job_not_found"},"409":{"description":"job_not_failed, or job_not_resumable with reason no_speech (charged:false)"},"422":{"description":"resume_unavailable, resume_not_supported, resume_media_expired"}}}},"/v1/jobs/{id}/result":{"get":{"summary":"Download a result with its expiring token.","responses":{"200":{"description":"File"}}}},"/v1/usage":{"get":{"security":[{"bearer":[]}],"summary":"Credits per day. Query from and to as unix milliseconds.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/captions/prepare":{"post":{"security":[{"bearer":[]}],"summary":"Return ASS for a browser render. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/brand-presets":{"get":{"security":[{"bearer":[]}],"summary":"Saved brand presets.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"security":[{"bearer":[]}],"summary":"Save a brand preset (name, fontFamily, color #RRGGBB, position, optional logoBase64 PNG/JPEG/WebP under 1 MB). Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/brand-presets/{id}":{"delete":{"security":[{"bearer":[]}],"summary":"Delete a brand preset. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/custom-presets":{"get":{"security":[{"bearer":[]}],"summary":"Your saved custom caption presets (full style JSON) with community review status. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"security":[{"bearer":[]}],"summary":"Save a full custom caption preset. Body: name, description?, and either style (full style document, same as list_presets style) or basePreset (id/slug/name/custom:cp_...) + overrides (deep-merged; null removes). 201 with id cp_... and preset custom:cp_... to pass as preset to burn, caption, preview, shorts, prepare, reviews. 422 invalid_style with errors [{path, message}]. Max 50 per key/account, 20 KB style. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"1-80 chars."},"description":{"type":"string","description":"Optional, max 500."},"style":{"type":"object"},"basePreset":{"type":"string","description":"Start from this preset."},"overrides":{"type":"object"}}}}}}}},"/v1/captions/style-preview":{"post":{"security":[{"bearer":[]}],"summary":"FREE preview before ordering, never charges, no transcription. Same body as POST /v1/captions (sourceUrl|fileId, preset or presets, language, translateTo, brandPresetId, styleOverrides, faceAvoid, highlightWords, highlightColor, platform, autoFit) plus preview-only text, fullText, atSeconds (number or up to 3), transcriptionJobId|subtitles. Renders each preset like the burn (same output size, autoFit, safe zone, words per caption, engine) on the real frame at each second (default: a frame with a face, else the middle). Returns sheetUrl (rows = seconds), presets[{id, name, frames[{atSeconds, url, truncated}], captionVideoArgs}]: send captionVideoArgs unchanged to POST /v1/captions to get that look. 30/hour and 200/day per key (up to 3 seconds = one sheet): 429 rate_limited with Retry-After. Identical repeats come from cache and do not count.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaUrl":{"type":"string","description":"Public https URL of the audio or video (direct file, Google Drive, Dropbox, or OneDrive share link). Up to 80 MB and 3 hours; a larger Content-Length is rejected before download.","format":"uri"},"fileId":{"type":"string","description":"Id from POST /v1/uploads/url (then PUT), POST /v1/uploads, or the MCP upload tools."},"durationSeconds":{"type":"number","description":"Optional duration hint. The job re-probes and bills the longer of the two."},"sourceUrl":{"type":"string","description":"Same as POST /v1/captions."},"preset":{"type":"string","description":"One preset."},"presets":{"type":"array","maxItems":12,"items":{"type":"string"}},"language":{"type":"string","description":"Spoken language; default sample phrase language."},"translateTo":{"type":"string","description":"As in POST /v1/captions; sample phrase in this language."},"brandPresetId":{"type":"string","description":"Saved brand preset."},"styleOverrides":{"type":"object","additionalProperties":true},"faceAvoid":{"type":"boolean","description":"Move captions off faces, like the burn."},"highlightWords":{"type":"array","items":{"type":"string"}},"highlightColor":{"type":"string","description":"#RRGGBB"},"platform":{"type":"string","description":"Safe-zone platform."},"autoFit":{"type":"boolean","description":"Default true."},"text":{"type":"string","description":"Preview only: sample phrase, max 80 chars."},"fullText":{"type":"boolean","description":"Preview only: all words in one caption (does not match a burn)."},"atSeconds":{"oneOf":[{"type":"number","minimum":0},{"type":"array","minItems":1,"maxItems":3,"items":{"type":"number","minimum":0}}],"description":"Preview only: second(s) to show; default a frame with a face."},"transcriptionJobId":{"type":"string","description":"Preview only: real captions from this transcription."},"subtitles":{"type":"string","description":"Preview only: SRT/VTT/JSON captions."},"audioVisual":{"type":"object","additionalProperties":false,"description":"Audio-only input (mp3, m4a, wav...): an editorial podcast design plus captions, drawn on the server by the web editor's own code, same price as the burn. {variant: swiss-grid | braun-radio | riso | editorial-cover | bauhaus | continuous-line | vinyl | type-wave | duotone-portrait | ma (default editorial-cover), showName (<=60), episode (<=12), speaker (<=60), coverImageUrl (https) or coverFileId (PNG/JPEG/WebP <=5 MB; shown by vinyl, duotone-portrait), background/accent/ink (#hex; ink auto from paper), captionMode integrated (default: the design typesets the captions) | preset (your caption preset draws), contrastGuard (default true), aspect 9:16|16:9|1:1|4:5 or width+height, overlays (<=8)}. Retired ids still work as aliases with a warning: bars→swiss-grid, ribbon→continuous-line, rings→ma, spectrogram→riso, skyline→bauhaus, silkline→type-wave, ivory→editorial-cover, halo→vinyl, needle→braun-radio, mono→duotone-portrait. On a video input: 422 audio_visual_needs_audio_input, not charged. Catalog: GET /v1/audio-visuals (MCP list_audio_visuals), free.","properties":{"variant":{"type":"string","enum":["swiss-grid","braun-radio","riso","editorial-cover","bauhaus","continuous-line","vinyl","type-wave","duotone-portrait","ma","bars","ribbon","rings","spectrogram","skyline","silkline","ivory","halo","needle","mono"],"default":"editorial-cover","description":"Design id. swiss-grid: Swiss grid; braun-radio: Braun radio; riso: Riso print; editorial-cover: Editorial cover; bauhaus: Bauhaus; continuous-line: Continuous line; vinyl: Vinyl; type-wave: Type as waveform; duotone-portrait: Duotone portrait; ma: Ma. Deprecated aliases (render their replacement, response carries warnings): bars→swiss-grid, ribbon→continuous-line, rings→ma, spectrogram→riso, skyline→bauhaus, silkline→type-wave, ivory→editorial-cover, halo→vinyl, needle→braun-radio, mono→duotone-portrait."},"enabled":{"type":"boolean","default":true,"description":"false: paper colour + captions only."},"showName":{"type":"string","maxLength":60,"description":"Show / podcast name. Used in mastheads, labels and seals. Empty: the element is omitted (masthead designs fall back to \"Podcast\")."},"episode":{"oneOf":[{"type":"string","maxLength":12},{"type":"number"}],"description":"Episode label or number, e.g. \"42\" or \"S2·E7\". Printed after Nº. Empty: omitted (Swiss grid shows the running timecode as its numeral)."},"speaker":{"type":"string","maxLength":60,"description":"Speaker / host name for bylines and name plates. Empty: omitted."},"coverImageUrl":{"type":"string","format":"uri","maxLength":2000,"description":"Public https URL of a PNG/JPEG/WebP (max 5 MB), fetched before any charge. Optional cover art or host photo (PNG/JPEG/WebP, max 5 MB). Used by designs that list it in `usesCover`; ignored by the others. Empty: the design draws its own graphic."},"coverFileId":{"type":"string","description":"fileId of an uploaded PNG/JPEG/WebP (max 5 MB), instead of coverImageUrl."},"background":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Paper (ground) colour, #rgb or #rrggbb. Default: the design's own paper. Text ink is picked automatically for contrast unless `ink` is set."},"accent":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Accent colour (#hex): the spoken word, needles, seals, rules. Default: the design's own accent."},"ink":{"type":"string","pattern":"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$","description":"Text/line colour (#hex). Default: the design's ink, or near-black/near-white chosen from the paper's luminance when `background` is changed."},"captionMode":{"type":"string","enum":["integrated","preset"],"default":"integrated","description":"integrated: the design typesets the transcript itself (pull-quote, word by word) and the caption preset is not drawn. preset: your caption preset draws as usual and the design keeps its caption band clear."},"contrastGuard":{"type":"boolean","default":true,"description":"preset mode only: when the preset's text colour has too little contrast with the paper (e.g. white text on a light design), the caption text switches to the design's ink and drops its stroke/shadow."},"aspect":{"type":"string","enum":["9:16","16:9","1:1","4:5"],"default":"9:16","description":"Frame shape; default from platform, else 9:16."},"width":{"type":"integer","minimum":128,"maximum":3840,"description":"With height: explicit frame size (long edge capped like the burn)."},"height":{"type":"integer","minimum":128,"maximum":3840},"overlays":{"type":"array","maxItems":8,"items":{"type":"object","additionalProperties":true},"description":"Up to 8 image (imageUrl/fileId, PNG/JPEG/WebP <=5 MB) or text items {kind, x, y, width, height, start, end, rotation, opacity, borderRadius, zIndex, style}."},"presetId":{"type":"string","deprecated":true,"description":"Retired (old bars presets): ignored with a warning."},"config":{"type":"object","deprecated":true,"additionalProperties":true,"description":"Retired (old visualizer config): ignored with a warning."}}}}}}}}}},"/v1/audio-visuals":{"get":{"security":[{"bearer":[]}],"summary":"Editorial podcast designs for audio-only input on POST /v1/captions, /v1/captions/burn and /v1/captions/style-preview (param audioVisual): for each of the ten designs its id, name, description, palette, the fields it uses, behaviour when fields are empty, fonts, recommended caption presets, a preview image URL and an example; plus field docs, defaults, the retired-id alias table, frame size per aspect, fps and pricing (same as the burn: 4 credits/min burn, 5 caption). No key needed. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/style-reference":{"get":{"security":[{"bearer":[]}],"summary":"Every caption style field with type, allowed values/range, description and JSON examples (wordStateStyles, wordHighlights, smartEmphasis, segmentColorCycle, caption forms). Use it to build styleOverrides or custom presets. No key needed. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/fonts":{"get":{"security":[{"bearer":[]}],"summary":"Font families bundled with web and server; the only fontFamily values custom and brand presets accept. Also in /v1/presets as fonts. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/custom-presets/validate":{"post":{"security":[{"bearer":[]}],"summary":"Validate style (or basePreset + overrides) without saving. 200 {valid:true, style} or 422 {valid:false, errors}. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/custom-presets/{id}":{"get":{"security":[{"bearer":[]}],"summary":"One custom preset. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"security":[{"bearer":[]}],"summary":"Update name, description, style (replace) or overrides (deep-merge). Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"security":[{"bearer":[]}],"summary":"Delete a custom preset. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/custom-presets/{id}/submit":{"post":{"security":[{"bearer":[]}],"summary":"Submit a custom preset for community review (202, status pending). Appears in /v1/presets only after a moderator approves it. Body: author?, description?, tags?, previewText?. Max 5/day. 409 already_submitted. Free.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/checkouts":{"post":{"security":[{"bearer":[]}],"summary":"Create a checkout. Empty body: $5 = 500 credits for this key (any key). With product (pack_20, pack_50, creator, pro, scale) and interval (month, year): needs a claimed key, else 409 account_required.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"product":{"type":"string","description":"Pack or plan slug."},"interval":{"type":"string","enum":["month","year"]}}}}}}}},"/v1/webhook-secret":{"get":{"security":[{"bearer":[]}],"summary":"The whsec_ secret for per-request webhookUrl signatures. Null until the first webhook job.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/keys/revoke":{"post":{"security":[{"bearer":[]}],"summary":"Revoke the current key.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/keys":{"get":{"security":[{"bearer":[]}],"summary":"List keys on the account.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"security":[{"bearer":[]}],"summary":"Create a key on the account. Token shown once.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/keys/{id}":{"delete":{"security":[{"bearer":[]}],"summary":"Revoke an account key.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/keys/{id}/rotate":{"post":{"security":[{"bearer":[]}],"summary":"Rotate an account key; the old token works for 24 hours.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/auth/magic-link":{"post":{"summary":"Email a one-time sign-in link.","responses":{"200":{"description":"Sent"}}}},"/v1/auth/verify":{"post":{"summary":"Exchange the magic-link token for a session token.","responses":{"200":{"description":"Session"}}}},"/v1/account":{"get":{"security":[{"bearer":[]}],"summary":"Account balance, plan, and settings (including webhookUrl, never the secret).","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"security":[{"bearer":[]}],"summary":"Update settings. webhookUrl (Pro and Scale) saves the account webhook; the secret is returned once.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"webhookUrl":{"type":["string","null"],"description":"Public https URL, or null to remove."}}}}}}}},"/v1/account/webhook/rotate":{"post":{"security":[{"bearer":[]}],"summary":"Rotate the account webhook secret (Pro and Scale). Returned once.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/account/claim-key":{"post":{"security":[{"bearer":[]}],"summary":"Move a key (and its credits) onto the signed-in account.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Full av_live_ key."}},"required":["token"]}}}}}},"/v1/account/portal":{"get":{"security":[{"bearer":[]}],"summary":"Billing portal link to manage plans, cards, and invoices.","responses":{"200":{"description":"OK"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/mcp":{"post":{"summary":"Streamable HTTP MCP. initialize, tools/list, create_key, quote, plan, and list_presets work without a key.","responses":{"200":{"description":"JSON-RPC"}}}},"/.well-known/mcp.json":{"get":{"summary":"MCP server card.","responses":{"200":{"description":"OK"}}}},"/llms.txt":{"get":{"summary":"Agent guide.","responses":{"200":{"description":"OK"}}}},"/openapi.json":{"get":{"summary":"This document.","responses":{"200":{"description":"OK"}}}}}}