{"openapi":"3.1.0","info":{"title":"Wyzie Subs API","version":"2026.11","summary":"Subtitles for movies and TV: search, download, translate, sync, transcribe, fix, extract.","description":"Send the TMDB or IMDB id of a movie or episode and get back every matching subtitle, each with a download link.\n\n**Keys.** Every request needs an API key as the `key` query parameter (form or JSON field on POST bodies). Free keys (1,000 requests a day) are claimed at https://sub.wyzie.io/redeem; Pro balances and subscriptions are at https://sub.wyzie.io. Browser keys (`wyzie-pub-` + 32 characters) are for front-end code and work only on /search, /c/ downloads, /quote and /sources.\n\n**Billing.** A search costs 1 request and each download costs 1 more. Other features are priced per use and stated in each operation. Free keys count against the daily allowance (X-RateLimit-*); Pro keys draw down a balance. Billed responses carry X-Wyzie-Cost (what this response was billed, 0 on refusals and free calls), X-Wyzie-Balance (requests left after it; an estimate between settlements, free keys settle every 15 s, Pro every 60 s) and X-Wyzie-Plan (`free` or `pro`). GET /usage shows the account and costs nothing.\n\n**Errors** are JSON `{ code, message, details }` with the matching HTTP status, plus extra fields where useful (`topup`, `upgrade`, `reset_at`, `reinstate`).","contact":{"name":"Wyzie","url":"https://sub.wyzie.io/contact"}},"externalDocs":{"description":"Wyzie Subs documentation","url":"https://docs.wyzie.io"},"servers":[{"url":"https://sub.wyzie.io","description":"Production"}],"security":[{"apiKey":[]}],"tags":[{"name":"Search","description":"Find subtitles for a title."},{"name":"Download","description":"Fetch subtitle files, with optional transforms."},{"name":"Translate","description":"AI translation."},{"name":"Quote","description":"Find a movie or episode from a line of dialogue."},{"name":"Meta","description":"Sources, languages, status and this document. Free."},{"name":"Sync","description":"Wyzie Synced: re-time a subtitle to your copy of the video (Pro)."},{"name":"Transcribe","description":"Speech to subtitles (Pro)."},{"name":"Fix","description":"Correct a subtitle against the speech of its video (Pro)."},{"name":"Extract","description":"Pull the subtitle tracks out of a video file."},{"name":"Account","description":"Usage and the balance webhook. Free."},{"name":"TMDB","description":"Title lookup used by the site's pickers. No key, capped per address."}],"paths":{"/search":{"get":{"operationId":"search","tags":["Search"],"summary":"Search subtitles by TMDB or IMDB id","description":"Returns an array of subtitles (see `Subtitle`), or one object / one file when `best` is set. Each result's `url` is a /c/ download link that carries its own `tok`; use it as is (download options may be appended).\n\nCost: 1 request. `best=1` is 1 request; `best=file` is 2 (search plus download). Cached results are billed the same. `video`, `hash`, `sort`, `page` and `limit` cost nothing extra. A search naming only paused providers gets an unbilled 503.\n\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"id","in":"query","required":true,"description":"TMDB or IMDB id of the movie or show. IMDB ids keep the `tt` prefix. A TMDB id is slower, the IMDB id is looked up first.","schema":{"type":"string","examples":["tt0111161","286217"]}},{"name":"season","in":"query","required":false,"description":"Season for TV (0 holds specials). Send together with episode.","schema":{"type":"integer","minimum":0}},{"name":"episode","in":"query","required":false,"description":"Episode for TV. Send together with season.","schema":{"type":"integer","minimum":0}},{"name":"language","in":"query","required":false,"description":"Language filter, ISO 639-1, comma separated. Also takes the AI codes such as pt-br or fil.","schema":{"type":"string","examples":["en","en,es"]}},{"name":"format","in":"query","required":false,"description":"Subtitle formats to return, comma separated (srt, vtt, ass, ssa, sub...).","schema":{"type":"string","examples":["srt","srt,vtt"]}},{"name":"encoding","in":"query","required":false,"description":"Character encoding filter, comma separated.","schema":{"type":"string","examples":["utf-8"]}},{"name":"hi","in":"query","required":false,"description":"When true (or 1), return only hearing-impaired subtitles. It is a filter, not a preference.","schema":{"type":"boolean"}},{"name":"source","in":"query","required":false,"description":"Providers to query by codename, comma separated, or `all` for every live source your key can use. Default charlie. Free keys: charlie and lima; Pro adds foxtrot, india, juliet, mike.","schema":{"type":"string","examples":["charlie","all"]}},{"name":"release","in":"query","required":false,"description":"Release or scene name filters, comma separated.","schema":{"type":"string"}},{"name":"filename","in":"query","required":false,"description":"Filename filters, comma separated (aliases: file, fileName). Filters the results; to rank them for one file use `video`.","schema":{"type":"string"}},{"name":"origin","in":"query","required":false,"description":"Content origin filter, comma separated (WEB, BLURAY, DVD...).","schema":{"type":"string","examples":["WEB,BLURAY"]}},{"name":"video","in":"query","required":false,"description":"Name of your video file. Ranks the results by how likely each fits it and adds `match` to every result. Cut at 300 characters; ignored when nothing in it is recognisable. Costs nothing extra.","schema":{"type":"string","examples":["Show.S02E03.1080p.WEB-DL.H.264-GROUP.mkv"]}},{"name":"hash","in":"query","required":false,"description":"OpenSubtitles movie hash (16 hex digits). Rows it names score 100 and go first. Checked against charlie only; ignored when malformed.","schema":{"type":"string","pattern":"^[0-9a-fA-F]{16}$"}},{"name":"sort","in":"query","required":false,"description":"`downloads` lists the most downloaded subtitles first; rows without a count go last.","schema":{"type":"string","enum":["downloads"]}},{"name":"page","in":"query","required":false,"description":"Page to return. Only used together with limit.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Results per page. Without it every result comes back in one response.","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"refresh","in":"query","required":false,"description":"true or 1 bypasses the result cache. Not available to browser keys.","schema":{"type":"boolean"}},{"name":"best","in":"query","required":false,"description":"`1`: answer ONE subtitle object (the best of the ranked results: text formats first unless `format` is given, non hearing-impaired first unless `hi=true`, never an AI row), 404 when nothing is usable; costs 1 request. `file`: answer the best file itself exactly like GET /download; costs 2 requests, and the download options apply.","schema":{"type":"string","enum":["1","file"]}},{"$ref":"#/components/parameters/opt_to"},{"$ref":"#/components/parameters/opt_offset"},{"$ref":"#/components/parameters/opt_shift"},{"$ref":"#/components/parameters/opt_fps"},{"$ref":"#/components/parameters/opt_plain"},{"$ref":"#/components/parameters/opt_sdh"},{"$ref":"#/components/parameters/opt_clean"},{"$ref":"#/components/parameters/opt_dual"},{"$ref":"#/components/parameters/opt_lines"},{"$ref":"#/components/parameters/opt_reflow"},{"$ref":"#/components/parameters/opt_maxlines"},{"$ref":"#/components/parameters/opt_mindur"}],"responses":{"200":{"description":"An array of subtitles. With `best=1` a single Subtitle object; with `best=file` the subtitle file itself (see GET /download).","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-Total-Count":{"description":"Total number of results before pagination.","schema":{"type":"integer"}},"X-Page":{"description":"Page returned (only with limit).","schema":{"type":"integer"}},"X-Per-Page":{"description":"The limit in effect (only with limit).","schema":{"type":"integer"}},"X-Total-Pages":{"description":"Total number of pages (only with limit).","schema":{"type":"integer"}},"X-Cache":{"$ref":"#/components/headers/XCache"},"X-Sources-Timed-Out":{"description":"Codenames of providers that timed out; the result set is incomplete.","schema":{"type":"string"}},"X-Sources-Offline":{"description":"Codenames of providers that were skipped because they are paused.","schema":{"type":"string"}},"X-Sources-Limited":{"description":"Keyless /download page only: why Pro sources were left out (`network` or `busy`).","schema":{"type":"string"}},"X-Subtitle-Url":{"description":"The /c/ link that was picked.","schema":{"type":"string"}},"X-Subtitle-Release":{"description":"Release name of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Source":{"description":"Source codename of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Language":{"description":"Language of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Transforms":{"$ref":"#/components/headers/XSubtitleTransforms"},"X-Ads-Removed":{"$ref":"#/components/headers/XAdsRemoved"},"X-Dual":{"description":"The second language that was merged in, or `unavailable` when none was found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"text/plain":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"text/vtt":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/ttml+xml":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/octet-stream":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/search/batch":{"post":{"operationId":"searchBatch","tags":["Search"],"summary":"Search up to 50 titles in one request","description":"JSON body with `items` (1 to 50). A string or number is an id; an object takes every /search parameter. Top-level `language`, `format`, `source`, `hi`, `best` and so on are defaults for items that do not set them.\n\nCost: 1 request per item, the same as one /search each. The whole batch is refused up front (401/402/403/429) when the key cannot pay. Browser keys are refused (403). \"No subtitles found\" is `ok: true` with an empty list (or `subtitle: null` with best), not an error.\n\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchBatchRequest"},"example":{"key":"YOUR_KEY","items":["tt0111161",286217,{"id":"tt0903747","season":1,"episode":1,"language":"es"}],"language":"en","best":false}}}},"responses":{"200":{"description":"One result per item, in order.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchBatchResponse"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/c/{vrf}/id/{fileId}":{"get":{"operationId":"downloadFile","tags":["Download"],"summary":"Download a subtitle file (the url of a search result)","description":"Take the `url` from a /search result as it is. The path (`vrf`, `fileId`) and the `tok` identify one file; a token copied off one link opens no other file, and `tok` never contains your key in readable form. Tokens last 60 days. Do not edit `format`, `encoding`, `id`, `season` or `episode` on the link; `autoUnzip=false` returns an archive as is.\n\nCost: 1 request per download, billed to the key that ran the search. `dual` costs 1 more, only when a second-language file was found. A bad option value is a 400 before billing; a Pro-only option on a free key is a 403 before billing; options on a file with no timed cues are a 422 (refunded). The ad filter strips provider ad cues; free keys get one short upsell cue at the start.\n\nContent-Type by format: srt, ass, sub, sbv and txt are `text/plain`, vtt is `text/vtt`, ttml is `application/ttml+xml`, json is `application/json`. The served file name takes the new extension.\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","security":[],"parameters":[{"name":"vrf","in":"path","required":true,"description":"Provider path segment from the search result url.","schema":{"type":"string"}},{"name":"fileId","in":"path","required":true,"description":"File identifier from the search result url.","schema":{"type":"string"}},{"name":"tok","in":"query","required":true,"description":"Download token carried by the link. Missing or expired is a 401.","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"Carried by the link; leave as is.","schema":{"type":"string"}},{"name":"encoding","in":"query","required":false,"description":"Carried by the link; leave as is.","schema":{"type":"string"}},{"name":"id","in":"query","required":false,"description":"Title id carried by the link (needed by `dual`).","schema":{"type":"string"}},{"name":"season","in":"query","required":false,"description":"Carried by the link for episodes.","schema":{"type":"integer"}},{"name":"episode","in":"query","required":false,"description":"Carried by the link for episodes.","schema":{"type":"integer"}},{"name":"autoUnzip","in":"query","required":false,"description":"false returns an archive as is instead of extracting the subtitle.","schema":{"type":"boolean","default":true}},{"$ref":"#/components/parameters/opt_to"},{"$ref":"#/components/parameters/opt_offset"},{"$ref":"#/components/parameters/opt_shift"},{"$ref":"#/components/parameters/opt_fps"},{"$ref":"#/components/parameters/opt_plain"},{"$ref":"#/components/parameters/opt_sdh"},{"$ref":"#/components/parameters/opt_clean"},{"$ref":"#/components/parameters/opt_dual"},{"$ref":"#/components/parameters/opt_lines"},{"$ref":"#/components/parameters/opt_reflow"},{"$ref":"#/components/parameters/opt_maxlines"},{"$ref":"#/components/parameters/opt_mindur"}],"responses":{"200":{"description":"The subtitle file.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"X-Subtitle-Url":{"description":"The /c/ link that was picked.","schema":{"type":"string"}},"X-Subtitle-Release":{"description":"Release name of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Source":{"description":"Source codename of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Language":{"description":"Language of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Transforms":{"$ref":"#/components/headers/XSubtitleTransforms"},"X-Ads-Removed":{"$ref":"#/components/headers/XAdsRemoved"},"X-Dual":{"description":"The second language that was merged in, or `unavailable` when none was found.","schema":{"type":"string"}},"X-Cache":{"$ref":"#/components/headers/XCache"}},"content":{"text/plain":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"text/vtt":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/ttml+xml":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/json":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/octet-stream":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"410":{"description":"The subtitle's provider has been retired. Search again for current links.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/download":{"get":{"operationId":"download","tags":["Download"],"summary":"One call: search, pick the best match, serve the file","description":"With a key, runs /search with the same filters (`language` defaults to `en`), picks the best match (the search's order, preferring SRT/WebVTT/ASS unless `format` is given, non-SDH unless `hi=true`, never an AI row) and serves it through its /c/ link with any download options. `X-Subtitle-Url`, `-Release`, `-Source` and `-Language` say what was picked.\n\nCost: 2 requests (search plus download), the same as doing both yourself; `dual` adds 1 when a second language was found. Refusals are /search's. Browser keys are refused (403). Without a key a browser gets the keyless download page and anything else a 401.\n\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"id","in":"query","required":true,"description":"TMDB or IMDB id of the movie or show. IMDB ids keep the `tt` prefix. A TMDB id is slower, the IMDB id is looked up first.","schema":{"type":"string","examples":["tt0111161","286217"]}},{"name":"season","in":"query","required":false,"description":"Season for TV (0 holds specials). Send together with episode.","schema":{"type":"integer","minimum":0}},{"name":"episode","in":"query","required":false,"description":"Episode for TV. Send together with season.","schema":{"type":"integer","minimum":0}},{"name":"language","in":"query","required":false,"description":"Language filter, ISO 639-1, comma separated. Also takes the AI codes such as pt-br or fil.","schema":{"type":"string","examples":["en","en,es"]}},{"name":"format","in":"query","required":false,"description":"Subtitle formats to return, comma separated (srt, vtt, ass, ssa, sub...).","schema":{"type":"string","examples":["srt","srt,vtt"]}},{"name":"encoding","in":"query","required":false,"description":"Character encoding filter, comma separated.","schema":{"type":"string","examples":["utf-8"]}},{"name":"hi","in":"query","required":false,"description":"When true (or 1), return only hearing-impaired subtitles. It is a filter, not a preference.","schema":{"type":"boolean"}},{"name":"source","in":"query","required":false,"description":"Providers to query by codename, comma separated, or `all` for every live source your key can use. Default charlie. Free keys: charlie and lima; Pro adds foxtrot, india, juliet, mike.","schema":{"type":"string","examples":["charlie","all"]}},{"name":"release","in":"query","required":false,"description":"Release or scene name filters, comma separated.","schema":{"type":"string"}},{"name":"filename","in":"query","required":false,"description":"Filename filters, comma separated (aliases: file, fileName). Filters the results; to rank them for one file use `video`.","schema":{"type":"string"}},{"name":"origin","in":"query","required":false,"description":"Content origin filter, comma separated (WEB, BLURAY, DVD...).","schema":{"type":"string","examples":["WEB,BLURAY"]}},{"name":"refresh","in":"query","required":false,"description":"true or 1 bypasses the result cache. Not available to browser keys.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/opt_to"},{"$ref":"#/components/parameters/opt_offset"},{"$ref":"#/components/parameters/opt_shift"},{"$ref":"#/components/parameters/opt_fps"},{"$ref":"#/components/parameters/opt_plain"},{"$ref":"#/components/parameters/opt_sdh"},{"$ref":"#/components/parameters/opt_clean"},{"$ref":"#/components/parameters/opt_dual"},{"$ref":"#/components/parameters/opt_lines"},{"$ref":"#/components/parameters/opt_reflow"},{"$ref":"#/components/parameters/opt_maxlines"},{"$ref":"#/components/parameters/opt_mindur"}],"responses":{"200":{"description":"The subtitle file.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-Subtitle-Url":{"description":"The /c/ link that was picked.","schema":{"type":"string"}},"X-Subtitle-Release":{"description":"Release name of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Source":{"description":"Source codename of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Language":{"description":"Language of the picked subtitle.","schema":{"type":"string"}},"X-Subtitle-Transforms":{"$ref":"#/components/headers/XSubtitleTransforms"},"X-Ads-Removed":{"$ref":"#/components/headers/XAdsRemoved"},"X-Dual":{"description":"The second language that was merged in, or `unavailable` when none was found.","schema":{"type":"string"}},"X-Cache":{"$ref":"#/components/headers/XCache"}},"content":{"text/plain":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"text/vtt":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/ttml+xml":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/json":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/octet-stream":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/translate":{"get":{"operationId":"translate","tags":["Translate"],"summary":"AI-translate a title's best subtitle ","description":"Wyzie finds a text subtitle for the title (preferring English SRT; VTT, ASS, SSA and SUB are converted to SRT first), translates it into `target` and streams the SRT back in order as batches finish. The full result is cached for 30 days.\n\nCost: 1 request, cache hits included. A failure before any output (no subtitle, search or download failure, busy server) is refunded. Free keys may translate too, up to 200 a day (429 after that, resets at midnight UTC; Pro keys have no daily limit). Browser keys are refused. Authenticate with `key`, or with the `tk` token carried by the `ai: true` rows of a /search.\n\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"id","in":"query","required":true,"description":"TMDB or IMDB id.","schema":{"type":"string"}},{"name":"target","in":"query","required":true,"description":"Language to translate into: a name or a code (see GET /languages).","schema":{"type":"string","examples":["Spanish","pt-BR"]}},{"name":"season","in":"query","required":false,"description":"Season for TV.","schema":{"type":"integer","minimum":0}},{"name":"episode","in":"query","required":false,"description":"Episode for TV.","schema":{"type":"integer","minimum":0}},{"name":"source","in":"query","required":false,"description":"Restrict the source subtitle to these providers (codenames).","schema":{"type":"string"}},{"name":"tk","in":"query","required":false,"description":"Token carried by the url of an `ai: true` search row; takes the place of `key`.","schema":{"type":"string"}},{"name":"refresh","in":"query","required":false,"description":"true or 1 skips the cache and translates again.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"The translated subtitle, SRT.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-Cache":{"$ref":"#/components/headers/XCache"},"X-Source-Language":{"description":"Language of the subtitle that was translated.","schema":{"type":"string"}},"X-Target-Language":{"description":"Language it was translated into.","schema":{"type":"string"}},"X-Source-Provider":{"description":"Provider that supplied the source subtitle.","schema":{"type":"string"}}},"content":{"text/plain":{"schema":{"type":"string","description":"SRT text."}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"502":{"description":"The search or the download of the source subtitle failed (refunded).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"$ref":"#/components/responses/Error503"}}}},"/quote":{"get":{"operationId":"quote","tags":["Quote"],"summary":"Find the movie or episode a line comes from","description":"Returns up to 10 hits, best first, one per movie or episode, from an index built out of subtitle traffic. Identical searches are cached for 10 minutes. At most 60 searches a minute per key. Without `q` and a key it serves the quote page.\n\nCost: 1 request on a Pro key; the code bills nothing for a free key's search (its day is not touched). Browser keys are billed to their account. A 503 (no index yet or busy) and a too-common line (400) are not billed.\n\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"q","in":"query","required":true,"description":"A line of dialogue (several words work best).","schema":{"type":"string"}},{"name":"language","in":"query","required":false,"description":"Language code, or `all`.","schema":{"type":"string","examples":["en","all"]}},{"name":"limit","in":"query","required":false,"description":"Maximum results.","schema":{"type":"integer","minimum":1,"maximum":10,"default":10}}],"responses":{"200":{"description":"Matching lines.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-Total-Count":{"description":"Number of hits returned.","schema":{"type":"integer"}},"X-Cache":{"$ref":"#/components/headers/XCache"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/QuoteResult"}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/sources":{"get":{"operationId":"sources","tags":["Meta"],"summary":"List the live subtitle sources","description":"Lists the providers that are enabled and passing their health checks, split into free and paid. With `key` the answer is scoped to what that key can use. Free and unmetered. Without a key it is cached for 60 s; with one it is never cached. Browser keys are accepted.","security":[],"parameters":[{"name":"key","in":"query","required":false,"description":"Optional. Adds a `key` object and `available` / `restricted` lists for this key.","schema":{"type":"string"}}],"responses":{"200":{"description":"The live sources.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourcesResponse"}}}},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/languages":{"get":{"operationId":"languages","tags":["Meta"],"summary":"List the AI translation languages","description":"The languages /translate (and the AI rows of /search) can produce, as code and name pairs. Either form works as `target`. Free and unmetered, cached for a day.","security":[],"responses":{"200":{"description":"Languages, sorted by name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LanguagesResponse"}}}},"429":{"$ref":"#/components/responses/Error429"}}}},"/status/api":{"get":{"operationId":"status","tags":["Meta"],"summary":"Status and uptime of the API and each provider","description":"Overall status, each provider's state, uptime over 24 h / 7 d / 30 d / 90 d, a per-day history, incidents from the last 30 days, and a shields.io endpoint badge with `format=shields`. Public, CORS open, cached 60 s. Free and unmetered.","security":[],"parameters":[{"name":"days","in":"query","required":false,"description":"Length of the per-day history. 0 leaves it out.","schema":{"type":"integer","minimum":0,"maximum":90,"default":90}},{"name":"format","in":"query","required":false,"description":"`shields` answers a shields.io endpoint badge instead of the report.","schema":{"type":"string","enum":["shields"]}},{"name":"source","in":"query","required":false,"description":"With format=shields, the badge for this provider codename.","schema":{"type":"string"}}],"responses":{"200":{"description":"The status report, or a shields badge with format=shields.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/StatusReport"},{"$ref":"#/components/schemas/ShieldsBadge"}]}}}},"404":{"description":"format=shields with an unknown source.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/Error429"}}}},"/sync":{"post":{"operationId":"sync","tags":["Sync"],"summary":"Re-time a subtitle to your video (Pro)","description":"Wyzie Synced listens to where people talk in your copy and works out the offset and frame-rate fix that line the subtitle up with it. Choose the subtitle with `url` (a /c/ link) or `id` + `language` (+ `season`/`episode`; the top 5 text subtitles are tried and the best fit wins). Give the audio as `speech` (`[[start, end], ...]` in seconds) or as the media file itself: the raw request body, or the multipart field `media` (buffered in memory, so capped at 200 MB by default). Fields may be query parameters, JSON or multipart fields. Cloudflare caps a request body at about 100 MB; for a whole movie use the chunked upload below.\n\nCost: 5 requests per successful sync (a key with fewer gets a 402 before any work); refusals and failed syncs are free. Downloading the returned link costs 1 more. The media is deleted when the sync ends and nothing about it is logged. `POST /synced` is the same API.\n\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"key","in":"query","required":false,"description":"Pro API key (or send it as a JSON or multipart field).","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncRequest"}},"multipart/form-data":{"schema":{"allOf":[{"$ref":"#/components/schemas/SyncRequest"}],"properties":{"media":{"type":"string","format":"binary","description":"The audio or video file."}}}},"application/octet-stream":{"schema":{"type":"string","format":"binary","description":"The media file as the raw body (fields in the query string)."}}}},"responses":{"200":{"description":"The synced download link.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResponse"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"411":{"description":"JSON and multipart bodies need a Content-Length.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/Error413"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/sync/upload":{"post":{"operationId":"syncUploadStart","tags":["Sync"],"summary":"Start a chunked upload for a big file (Pro)","description":"Starts an upload session for media over the single-request limit. Then send each piece to `POST /sync/upload/{id}` with `X-Chunk-Index: 0, 1, 2...` and finish with `POST /sync/upload/{id}/finish`. Sessions expire after 30 minutes. Cost: nothing here; the sync is charged when it succeeds (5 requests). wyzie-lib's `syncSubtitle` does this for you.","parameters":[{"name":"key","in":"query","required":true,"description":"Pro API key.","schema":{"type":"string"}}],"responses":{"200":{"description":"The session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncUploadSession"}}}},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/sync/upload/{id}":{"post":{"operationId":"syncUploadChunk","tags":["Sync"],"summary":"Append one chunk to an upload","description":"The body is the raw bytes of the next chunk, at most `chunkMaxBytes`. Send chunks in order; a mismatched `X-Chunk-Index` gets a 409 naming the index actually expected, so a retry resumes cleanly. Cost: nothing.","parameters":[{"name":"id","in":"path","required":true,"description":"The `uploadId` from the start call.","schema":{"type":"string"}},{"name":"key","in":"query","required":true,"description":"The key that started the upload.","schema":{"type":"string"}},{"name":"X-Chunk-Index","in":"header","required":true,"description":"0, 1, 2... in order.","schema":{"type":"integer","minimum":0}}],"requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"The chunk was stored.","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"integer","description":"Bytes stored."},"index":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"description":"Wrong chunk index; `expectedIndex` says which one is next.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/Error413"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/sync/upload/{id}/finish":{"post":{"operationId":"syncUploadFinish","tags":["Sync"],"summary":"Run the sync on everything uploaded","description":"Takes the same fields as POST /sync (JSON body or query string) except the media, which is what you uploaded, and runs the sync. The session is deleted either way. Cost: 5 requests when the sync succeeds, otherwise nothing.","parameters":[{"name":"id","in":"path","required":true,"description":"The `uploadId` from the start call.","schema":{"type":"string"}},{"name":"key","in":"query","required":false,"description":"The key that started the upload.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncRequest"}}}},"responses":{"200":{"description":"The synced download link.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResponse"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/transcribe":{"post":{"operationId":"transcribe","tags":["Transcribe"],"summary":"Turn speech in your audio or video into subtitles (Pro)","description":"Send the file as the raw request body or the multipart field `media` (up to 100 MB through Cloudflare, so send the audio track only for a long video: `ffmpeg -i video.mp4 -vn -ac 1 -b:a 48k audio.m4a`). Up to 4 hours of audio. Options are query parameters or multipart fields. A job that finishes within 50 s returns the file; a slower one returns 202 and is polled at `GET /transcribe/{id}`.\n\nCost: 6,000 requests per started 30 minutes of audio (under 30 minutes is 6,000, 45 minutes is 12,000); speakers=1 uses 60,000 per block instead; sounds=1 adds 100 per block; translate adds a flat 25. Charged when the job starts, refunded in full on a failure on our side; a file with no speech stays charged. Bad input is refused free. Pro keys only.\n\nResult headers: `x-wyzie-cost`, `x-wyzie-duration`, `x-wyzie-language`, `x-wyzie-cache` (hit or miss). At most 20 transcriptions per key per hour.\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"key","in":"query","required":true,"description":"Pro API key (or a multipart field).","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"Output format. Default srt.","schema":{"$ref":"#/components/schemas/TranscribeFormat"}},{"name":"language","in":"query","required":false,"description":"Spoken language, ISO 639-1. Detected when left out. Required with speakers=1.","schema":{"type":"string","pattern":"^[a-z]{2}$"}},{"name":"speakers","in":"query","required":false,"description":"1 labels who is speaking ([Speaker 1]). Uses Deepgram Nova-3, needs `language` set to one of de en es fr hi it ja nl pt ru, and costs 60,000 per started 30 minutes instead of 6,000.","schema":{"type":"boolean"}},{"name":"sounds","in":"query","required":false,"description":"1 (beta) adds sound tags such as [Music] and [Applause] between speech. Costs 100 more per started 30 minutes. Single files only.","schema":{"type":"boolean"}},{"name":"translate","in":"query","required":false,"description":"Language name or code (see /languages) to translate the result into. Flat 25 requests extra.","schema":{"type":"string","examples":["Spanish","pt-BR"]}},{"name":"cache","in":"query","required":false,"description":"0 keeps this audio out of the recognition cache. The price is the same either way.","schema":{"type":"boolean"}},{"name":"webhook","in":"query","required":false,"description":"https URL to receive one signed JSON POST when the job ends. A 400 before any charge when the URL is not usable. The signing secret comes back as `webhookSecret` (202) or the `x-wyzie-webhook-secret` header.","schema":{"type":"string","format":"uri"}}],"requestBody":{"required":true,"description":"The audio or video file.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"multipart/form-data":{"schema":{"type":"object","required":["media"],"properties":{"media":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"The subtitle, in the requested format (`txt` and `json` are described in TranscribeJson).","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"x-wyzie-duration":{"description":"Seconds of audio.","schema":{"type":"integer"}},"x-wyzie-language":{"description":"Detected or given language.","schema":{"type":"string"}},"x-wyzie-cache":{"description":"Whether recognition was reused.","schema":{"type":"string","enum":["hit","miss"]}},"x-wyzie-webhook-secret":{"description":"Webhook signing secret, when a webhook was set.","schema":{"type":"string"}}},"content":{"text/plain":{"schema":{"type":"string"}},"text/vtt":{"schema":{"type":"string"}},"application/ttml+xml":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeJson"}}}},"202":{"description":"Still running. Poll the `poll` URL.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeJob202"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"413":{"$ref":"#/components/responses/Error413"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/transcribe/{id}":{"get":{"operationId":"transcribePoll","tags":["Transcribe"],"summary":"Poll a transcription (or a fix) job","description":"Only the key that started the job can read it. Returns the finished file, a 202 while it runs, or the failure. Jobs are kept for 1 hour after they end. Cost: nothing.","parameters":[{"name":"id","in":"path","required":true,"description":"Job id.","schema":{"type":"string"}},{"name":"key","in":"query","required":true,"description":"The key that started the job.","schema":{"type":"string"}}],"responses":{"200":{"description":"The finished subtitle.","headers":{"x-wyzie-cost":{"$ref":"#/components/headers/XWyzieCost"}},"content":{"text/plain":{"schema":{"type":"string"}},"text/vtt":{"schema":{"type":"string"}},"application/ttml+xml":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeJson"}}}},"202":{"description":"Still running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeJob202"}}}},"401":{"$ref":"#/components/responses/Error401"},"404":{"$ref":"#/components/responses/Error404"},"413":{"$ref":"#/components/responses/Error413"},"422":{"$ref":"#/components/responses/Error422"},"503":{"$ref":"#/components/responses/Error503"}}}},"/transcribe/url":{"post":{"operationId":"transcribeUrl","tags":["Transcribe"],"summary":"Transcribe the audio of a link (Pro)","description":"The server fetches the audio itself: a media file, an HLS or DASH stream, or a page on a site yt-dlp reads (YouTube, Vimeo, Twitch and a few more; sites that block datacenter fetching fail and are refunded). Up to 24 hours of media. Returns 202 and is polled at `GET /transcribe/{id}`. `dryRun: true` answers the estimate and charges nothing.\n\nCost: 6,000 requests per started 30 minutes of audio (under 30 minutes is 6,000, 45 minutes is 12,000); speakers=1 uses 60,000 per block instead; sounds=1 adds 100 per block; translate adds a flat 25. Charged when the job starts, refunded in full on a failure on our side; a file with no speech stays charged. Bad input is refused free. Pro keys only. Everything is validated before the charge.\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeUrlRequest"},"example":{"key":"YOUR_KEY","url":"https://example.com/audio.mp3","format":"srt","dryRun":true}}}},"responses":{"200":{"description":"dryRun: the estimate. Nothing was charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeUrlEstimate"}}}},"202":{"description":"The job started.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeUrlJob202"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"413":{"$ref":"#/components/responses/Error413"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/transcribe/url/probe":{"get":{"operationId":"transcribeUrlProbe","tags":["Transcribe"],"summary":"Check a link before transcribing it","description":"What Transcribe from URL would do with a link. A link we cannot use is `supported: false` with a short reason, never a 5xx. Any valid key; at most 30 probes a minute per key. Cost: nothing. The estimate is for plain transcription unless `speakers`, `sounds` or `translate` are given.","parameters":[{"name":"url","in":"query","required":true,"description":"The link to check.","schema":{"type":"string","format":"uri"}},{"name":"speakers","in":"query","required":false,"description":"Add the speaker-labels surcharge to the estimate.","schema":{"type":"boolean"}},{"name":"sounds","in":"query","required":false,"description":"Add the sound-tags surcharge to the estimate.","schema":{"type":"boolean"}},{"name":"translate","in":"query","required":false,"description":"Add the translation surcharge to the estimate.","schema":{"type":"string"}}],"responses":{"200":{"description":"The verdict.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeUrlProbe"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"}}}},"/transcribe/batch":{"post":{"operationId":"transcribeBatch","tags":["Transcribe"],"summary":"Transcribe a podcast feed or up to 50 links (Pro)","description":"JSON body with `feed` (an RSS or Atom URL; its newest `limit` items, 1 to 50, default 10) or `urls` (up to 50 media links), plus `format`, `language`, `speakers`, `translate`, `cache` applied to every item. `sounds` is not available in bulk. `dryRun: true` lists the items and an estimate without charging. Returns 202; read progress at `GET /transcribe/batch/{id}`.\n\nCost: the sum of its items, each priced like a single transcription and charged when it starts. The first 402 stops the batch and the rest are skipped, uncharged. Results and the encrypted key are held in Redis for 24 hours.\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeBatchRequest"},"example":{"key":"YOUR_KEY","urls":["https://example.com/ep1.mp3"],"format":"srt","dryRun":true}}}},"responses":{"200":{"description":"dryRun: the items and the estimate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeBatchDryRun"}}}},"202":{"description":"The batch started.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeBatch202"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"413":{"$ref":"#/components/responses/Error413"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/transcribe/batch/{id}":{"get":{"operationId":"transcribeBatchStatus","tags":["Transcribe"],"summary":"Progress of a bulk transcription","description":"Each item's status, cost and result link. Only the key that started the batch can read it. Batches are kept for 24 hours. Cost: nothing.","parameters":[{"name":"id","in":"path","required":true,"description":"Batch id.","schema":{"type":"string"}},{"name":"key","in":"query","required":true,"description":"The key that started the batch.","schema":{"type":"string"}}],"responses":{"200":{"description":"The batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeBatchStatus"}}}},"401":{"$ref":"#/components/responses/Error401"},"404":{"$ref":"#/components/responses/Error404"}}}},"/transcribe/batch/{id}/{index}":{"get":{"operationId":"transcribeBatchItem","tags":["Transcribe"],"summary":"One finished item's subtitle","description":"Cost: nothing. 404 `Not ready` while the item has no subtitle.","parameters":[{"name":"id","in":"path","required":true,"description":"Batch id.","schema":{"type":"string"}},{"name":"index","in":"path","required":true,"description":"Item index, from 0.","schema":{"type":"integer","minimum":0}},{"name":"key","in":"query","required":true,"description":"The key that started the batch.","schema":{"type":"string"}}],"responses":{"200":{"description":"The subtitle, in the batch's format.","content":{"text/plain":{"schema":{"type":"string"}},"text/vtt":{"schema":{"type":"string"}},"application/ttml+xml":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeJson"}}}},"401":{"$ref":"#/components/responses/Error401"},"404":{"$ref":"#/components/responses/Error404"}}}},"/transcribe/batch/{id}/zip":{"get":{"operationId":"transcribeBatchZip","tags":["Transcribe"],"summary":"Every finished subtitle of a batch, zipped","description":"Everything finished so far. Cost: nothing. 404 `Nothing finished yet` when empty.","parameters":[{"name":"id","in":"path","required":true,"description":"Batch id.","schema":{"type":"string"}},{"name":"key","in":"query","required":true,"description":"The key that started the batch.","schema":{"type":"string"}}],"responses":{"200":{"description":"A zip archive.","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Error401"},"404":{"$ref":"#/components/responses/Error404"}}}},"/fix":{"post":{"operationId":"fix","tags":["Fix"],"summary":"Correct a subtitle against the speech of its video (Pro)","description":"Corrects wrong words, re-times lines and adds missing lines by comparing a subtitle with the speech of its video. Send the video (or its audio track) as the raw body or multipart `media`, plus the subtitle as the multipart field `subtitle`, or `url` (a /c/ link), or `id` + `language` (+ `season`, `episode`). Long jobs return 202 and are polled at `GET /fix/{id}` (or `GET /transcribe/{id}`).\n\nCost: priced like Transcribe, 6,000 requests per started 30 minutes of audio, charged when the job starts and refunded in full if we fail. A subtitle found after recognition to be in another language or the wrong one for the video stays charged; it is free only when `language` is given and clearly differs, which is refused before the charge. Pro keys only.\n\nResult headers: `x-wyzie-cost`, `-duration`, `-language`, `-lines-corrected`, `-lines-retimed`, `-lines-added`, `-lines-total`.\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"key","in":"query","required":true,"description":"Pro API key (or a multipart field).","schema":{"type":"string"}},{"name":"url","in":"query","required":false,"description":"A /c/ download link for the subtitle to fix.","schema":{"type":"string"}},{"name":"id","in":"query","required":false,"description":"With language: pick the best of the top search results.","schema":{"type":"string"}},{"name":"language","in":"query","required":false,"description":"Spoken language of the video (and of the subtitle). Detected when left out.","schema":{"type":"string","pattern":"^[a-z]{2}$"}},{"name":"season","in":"query","required":false,"description":"With id, for TV.","schema":{"type":"integer"}},{"name":"episode","in":"query","required":false,"description":"With id, for TV.","schema":{"type":"integer"}},{"name":"format","in":"query","required":false,"description":"Output format; the subtitle's own format by default. No txt or json (`report=1` is the JSON).","schema":{"type":"string","enum":["srt","vtt","ass","sbv","ttml"]}},{"name":"retime","in":"query","required":false,"description":"1 (default) moves cues to when the words are said; 0 keeps the times.","schema":{"type":"boolean","default":true}},{"name":"report","in":"query","required":false,"description":"1 answers JSON `{ subtitle, changes: [{ start, before, after, kind }] }`.","schema":{"type":"boolean"}},{"name":"cache","in":"query","required":false,"description":"0 keeps this audio out of the recognition cache.","schema":{"type":"boolean"}},{"name":"webhook","in":"query","required":false,"description":"https URL to receive one signed JSON POST when the job ends. A 400 before any charge when the URL is not usable. The signing secret comes back as `webhookSecret` (202) or the `x-wyzie-webhook-secret` header.","schema":{"type":"string","format":"uri"}}],"requestBody":{"required":true,"description":"The video or its audio. Multipart may also carry `subtitle` (the file).","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"multipart/form-data":{"schema":{"type":"object","required":["media"],"properties":{"media":{"type":"string","format":"binary"},"subtitle":{"type":"string","format":"binary","description":"SRT, WebVTT, ASS/SSA, MicroDVD or TTML, up to 8 MB."}}}}}},"responses":{"200":{"description":"The corrected subtitle, or the change report with report=1.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"x-wyzie-lines-corrected":{"schema":{"type":"integer"}},"x-wyzie-lines-retimed":{"schema":{"type":"integer"}},"x-wyzie-lines-added":{"schema":{"type":"integer"}},"x-wyzie-lines-total":{"schema":{"type":"integer"}}},"content":{"text/plain":{"schema":{"type":"string"}},"text/vtt":{"schema":{"type":"string"}},"application/ttml+xml":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/FixReport"}}}},"202":{"description":"Still running. Poll the `poll` URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeJob202"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"413":{"$ref":"#/components/responses/Error413"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/fix/{id}":{"get":{"operationId":"fixPoll","tags":["Fix"],"summary":"Poll a fix job","description":"Only the key that started the job can read it. Results are kept for 1 hour after the job ends. Cost: nothing.","parameters":[{"name":"id","in":"path","required":true,"description":"Job id.","schema":{"type":"string"}},{"name":"key","in":"query","required":true,"description":"The key that started the job.","schema":{"type":"string"}}],"responses":{"200":{"description":"The corrected subtitle, or the report.","content":{"text/plain":{"schema":{"type":"string"}},"text/vtt":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/FixReport"}}}},"202":{"description":"Still running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscribeJob202"}}}},"401":{"$ref":"#/components/responses/Error401"},"404":{"$ref":"#/components/responses/Error404"},"422":{"$ref":"#/components/responses/Error422"},"503":{"$ref":"#/components/responses/Error503"}}}},"/extract":{"post":{"operationId":"extract","tags":["Extract"],"summary":"Pull subtitle tracks out of a video file","description":"Reads the embedded subtitle tracks of an MKV, MP4, WebM, MKS or any container ffmpeg reads. The file is the raw request body or the multipart field `media`. Cloudflare caps a request body at about 100 MB, so for a big film send only the subtitle tracks: `ffmpeg -i movie.mkv -map 0:s -c copy subs.mks`.\n\n`list=1` answers JSON and extracts nothing. `track=<index>` or `language=<ISO 639-1 or 639-2>` picks the text track (default: the first). The track is served as a file in its own format (subrip becomes srt, ass/ssa ass, webvtt vtt, mov_text srt) and every download option applies. `all=1` serves every text track as a zip (`<name>.<lang>.<ext>`).\n\nCost: 1 request per track served (`all=1`: one per track in the zip); `list=1` costs 1. Charged after the probe succeeded; a file with no tracks (422) costs nothing. Any valid key, free or Pro; browser keys are refused. At most 60 extractions per key per hour.\n\nResponse headers: `X-Subtitle-Track` (index), `X-Subtitle-Language` (3-letter code or `und`), `X-Subtitle-Codec`, `X-Extract-Tracks` (number of text tracks in the file).\nBilling: free keys have 1,000 requests a day; Pro keys draw from a balance (subscription allowance plus top-ups). Every billed response carries X-Wyzie-Cost, X-Wyzie-Balance and X-Wyzie-Plan.","parameters":[{"name":"key","in":"query","required":true,"description":"API key (or a multipart field).","schema":{"type":"string"}},{"name":"list","in":"query","required":false,"description":"1 lists the tracks as JSON.","schema":{"type":"boolean"}},{"name":"track","in":"query","required":false,"description":"Subtitle-stream index to extract (0-based, file order).","schema":{"type":"integer","minimum":0}},{"name":"language","in":"query","required":false,"description":"Pick the first text track in this language.","schema":{"type":"string"}},{"name":"all","in":"query","required":false,"description":"1 serves every text track as a zip.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/opt_to"},{"$ref":"#/components/parameters/opt_offset"},{"$ref":"#/components/parameters/opt_shift"},{"$ref":"#/components/parameters/opt_fps"},{"$ref":"#/components/parameters/opt_plain"},{"$ref":"#/components/parameters/opt_sdh"},{"$ref":"#/components/parameters/opt_clean"},{"$ref":"#/components/parameters/opt_dual"},{"$ref":"#/components/parameters/opt_lines"},{"$ref":"#/components/parameters/opt_reflow"},{"$ref":"#/components/parameters/opt_maxlines"},{"$ref":"#/components/parameters/opt_mindur"}],"requestBody":{"required":true,"description":"The video, or a file holding just its subtitle tracks.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"multipart/form-data":{"schema":{"type":"object","required":["media"],"properties":{"media":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"The track file, a zip with all=1, or the track list with list=1.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"},"X-Subtitle-Track":{"description":"Index of the track served.","schema":{"type":"integer"}},"X-Subtitle-Language":{"description":"3-letter code or `und`.","schema":{"type":"string"}},"X-Subtitle-Codec":{"schema":{"type":"string"}},"X-Extract-Tracks":{"description":"Number of text tracks in the file.","schema":{"type":"integer"}},"X-Subtitle-Transforms":{"$ref":"#/components/headers/XSubtitleTransforms"}},"content":{"text/plain":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"text/vtt":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/ttml+xml":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/json":{"schema":{"$ref":"#/components/schemas/ExtractList"}},"application/octet-stream":{"schema":{"type":"string","description":"The subtitle file, in the requested or original format."}},"application/zip":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"402":{"$ref":"#/components/responses/Error402"},"403":{"$ref":"#/components/responses/Error403"},"413":{"$ref":"#/components/responses/Error413"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/usage":{"get":{"operationId":"usage","tags":["Account"],"summary":"Balance and per-day usage of a key","description":"The key type, balance, today's use, subscription state, the balance webhook and a per-day breakdown by route and source. Cost: nothing. Browser keys are refused. The per-day breakdown is kept by the API server for 30 days; days with no traffic are omitted; the balance comes from the billing database and is authoritative.","parameters":[{"name":"key","in":"query","required":true,"description":"Your API key.","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"How many days of breakdown.","schema":{"type":"integer","minimum":1,"maximum":30,"default":30}}],"responses":{"200":{"description":"The usage report.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}}}},"/usage/webhook":{"put":{"operationId":"usageWebhookSet","tags":["Account"],"summary":"Set the low-balance webhook","description":"Sets the account's balance webhook (`POST` works too, and the fields may be query parameters). Pro and free keys; browser keys are refused. Cost: nothing.\n\nEvents, one JSON POST each, retried after 30 s, 5 min and 30 min: `balance.low` (Pro: the balance fell to 20% of the current pool or under), `balance.depleted` (Pro: it reached 0), `limit.reached` (free: today's 1,000 are used). Each fires once per drawdown. The `secret` is the same one that signs Transcribe webhooks for this key (HMAC-SHA256, header `x-wyzie-signature: t=<unix>,v1=<hex>` over `t.body`). Independent of the email toggles.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageWebhookRequest"},"example":{"key":"YOUR_KEY","url":"https://example.com/wyzie-balance"}}}},"responses":{"200":{"description":"The webhook is set.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageWebhook"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"}}},"delete":{"operationId":"usageWebhookClear","tags":["Account"],"summary":"Remove the low-balance webhook","description":"Cost: nothing. Browser keys are refused.","parameters":[{"name":"key","in":"query","required":true,"description":"Your API key.","schema":{"type":"string"}}],"responses":{"200":{"description":"The webhook was removed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"}}}},"/api/tmdb/search":{"get":{"operationId":"tmdbSearch","tags":["TMDB"],"summary":"Search titles by name","description":"The title picker's lookup: up to 10 movies and shows matching a name, so you can get a TMDB id for /search. Needs no key and costs nothing, but is capped per address (600 an hour, 3,000 a day); do not use it as a TMDB proxy.","security":[],"parameters":[{"name":"q","in":"query","required":true,"description":"The title (alias: query). 2 to 150 characters.","schema":{"type":"string","minLength":2,"maxLength":150}},{"name":"language","in":"query","required":false,"description":"TMDB locale for titles and overviews.","schema":{"type":"string","default":"en-US"}}],"responses":{"200":{"description":"Matches.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TmdbSearchResponse"}}}},"400":{"$ref":"#/components/responses/Error400"},"429":{"$ref":"#/components/responses/Error429"},"502":{"description":"TMDB failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"TMDB timed out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tmdb/tv/{id}":{"get":{"operationId":"tmdbTv","tags":["TMDB"],"summary":"Seasons of a TV show","description":"No key, free, capped per address like /api/tmdb/search.","security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"TMDB id of the show.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"The show's seasons.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TmdbTv"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"}}}},"/api/tmdb/tv/{id}/{season}":{"get":{"operationId":"tmdbSeason","tags":["TMDB"],"summary":"Episodes of a season","description":"No key, free, capped per address like /api/tmdb/search.","security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"TMDB id of the show.","schema":{"type":"integer","minimum":1}},{"name":"season","in":"path","required":true,"description":"Season number.","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"The season's episodes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TmdbSeason"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"}}}},"/openapi.json":{"get":{"operationId":"openapi","tags":["Meta"],"summary":"This document","description":"The OpenAPI 3.1 document for the public API. CORS open, cached for an hour. Free and unmetered.","security":[],"responses":{"200":{"description":"The OpenAPI document.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"$ref":"#/components/responses/Error429"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"query","name":"key","description":"Your API key. Free keys: https://sub.wyzie.io/redeem. Pro: https://sub.wyzie.io. On POST endpoints the key may also be a JSON or form field."}},"headers":{"XWyzieCost":{"description":"Requests this response was billed (0 on refusals and free calls).","schema":{"type":"integer"}},"XWyzieBalance":{"description":"Requests left after it. Pro: balance (subscription plus top-ups). Free: left today. An estimate between settlements.","schema":{"type":"integer"}},"XWyziePlan":{"description":"The key's plan.","schema":{"type":"string","enum":["free","pro"]}},"XRateLimitLimit":{"description":"Free keys: the daily allowance.","schema":{"type":"integer"}},"XRateLimitRemaining":{"description":"Free keys: requests left today. Pro keys: requests left in the balance.","schema":{"type":"integer"}},"XRateLimitReset":{"description":"Free keys only: Unix epoch seconds when the daily window rolls over (UTC midnight). Not ISO 8601.","schema":{"type":"integer"}},"XSubtitleTransforms":{"description":"What download options were applied, with counts, e.g. `to=vtt; shift=2.5; lines=42(17)`.","schema":{"type":"string"}},"XAdsRemoved":{"description":"true when a provider ad cue was stripped.","schema":{"type":"string"}},"XCache":{"description":"HIT, HIT-REDIS or MISS.","schema":{"type":"string"}},"RetryAfter":{"description":"Seconds to wait.","schema":{"type":"integer"}}},"parameters":{"opt_to":{"name":"to","in":"query","required":false,"description":"Output format (all plans). `vtt` plays in a browser <track>. `txt` is plain text, one cue per line, no timing. `json` is `{ format, cues: [{ start, end, text }] }` in seconds. `sub` (MicroDVD) uses the frame rate from `fps` when given, else 25. `dfxp` is the same as `ttml`. Default: the file's own format.","schema":{"type":"string","enum":["srt","vtt","ass","sub","sbv","ttml","dfxp","txt","json"]}},"opt_offset":{"name":"offset","in":"query","required":false,"description":"Shift every cue by this many seconds (negative is earlier). All plans.","schema":{"type":"number","minimum":-3600,"maximum":3600}},"opt_shift":{"name":"shift","in":"query","required":false,"description":"Alias of `offset`: seconds unless `ms` or a clock time is given (`+2.5s`, `-1.5`, `-1500ms`, `01:02.500`, `-00:00:02.500`). Range 3600 s either way. All plans.","schema":{"type":"string","examples":["+2.5s","-1500ms","01:02.500"]}},"opt_fps":{"name":"fps","in":"query","required":false,"description":"Fix drift from a subtitle made for another release: SUBTITLE_FPS:VIDEO_FPS, each 1 to 120. All plans.","schema":{"type":"string","examples":["25:23.976"]}},"opt_plain":{"name":"plain","in":"query","required":false,"description":"1 strips styling codes, drops empty and repeated cues, sorts, trims small overlaps. All plans.","schema":{"type":"boolean"}},"opt_sdh":{"name":"sdh","in":"query","required":false,"description":"strip removes hearing-impaired text ([DOOR SLAMS], (sighs), JOHN: labels, music lyrics). Pro.","schema":{"type":"string","enum":["strip"]}},"opt_clean":{"name":"clean","in":"query","required":false,"description":"1 masks strong profanity, keeping the first letter (English files). Pro.","schema":{"type":"boolean"}},"opt_dual":{"name":"dual","in":"query","required":false,"description":"Add a second language (ISO 639-1) under each line. Pro. Costs 1 extra request only when a second-language file was found; otherwise the file comes back alone with `X-Dual: unavailable`.","schema":{"type":"string","pattern":"^[a-z]{2}$","examples":["ja"]}},"opt_lines":{"name":"lines","in":"query","required":false,"description":"Reflow: rewrap each cue to at most this many characters per line (balanced), at most `maxlines` lines; a cue that still does not fit is split into consecutive cues with proportional timing. All plans.","schema":{"type":"integer","minimum":10,"maximum":100}},"opt_reflow":{"name":"reflow","in":"query","required":false,"description":"Same as lines=42. All plans.","schema":{"type":"string","enum":["1"]}},"opt_maxlines":{"name":"maxlines","in":"query","required":false,"description":"With `lines` or `reflow`: most lines per cue. All plans.","schema":{"type":"integer","minimum":1,"maximum":3,"default":2}},"opt_mindur":{"name":"mindur","in":"query","required":false,"description":"Minimum display time in seconds: a shorter cue is extended, never into the next cue. All plans.","schema":{"type":"number","minimum":0.2,"maximum":10}}},"responses":{"Error400":{"description":"Bad request: a missing or invalid parameter or body. Refused before billing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error401":{"description":"API key required (download links: missing or expired tok).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error402":{"description":"Pro balance exhausted or too low for this call. `topup` links to https://sub.wyzie.io/topup.","headers":{"X-Wyzie-Cost":{"$ref":"#/components/headers/XWyzieCost"},"X-Wyzie-Balance":{"$ref":"#/components/headers/XWyzieBalance"},"X-Wyzie-Plan":{"$ref":"#/components/headers/XWyziePlan"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error403":{"description":"Invalid key, a Pro-only feature on a free key, a feature not open to browser keys, or the key is on hold (`reinstate`, `support`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error404":{"description":"Nothing found, or no such job for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error413":{"description":"The file or body is too large.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error422":{"description":"The input cannot be used: no audio or speech, no timed cues, not a media file, or a link we cannot fetch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error429":{"description":"Free key over its daily limit (`upgrade`, `reset_at`), or a per-key, per-address or per-route cap.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Error503":{"description":"Busy, restarting, or an upstream is unavailable. Not billed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","required":["code","message"],"description":"Every error body. Extra fields appear where useful.","properties":{"code":{"type":"integer","description":"The HTTP status."},"message":{"type":"string"},"details":{"type":"string"},"example":{"type":"string","description":"An example request, on parameter errors."},"topup":{"type":"string","format":"uri","description":"402: where to add requests."},"upgrade":{"type":"string","format":"uri","description":"429 and 403: where to upgrade."},"reset_at":{"type":"integer","description":"429: Unix epoch seconds when the daily window resets (same as X-RateLimit-Reset)."},"reinstate":{"type":"string","format":"uri","description":"403 key on hold."},"support":{"type":"string","format":"uri"},"reason":{"type":"string","description":"422 from /transcribe/url: why the link cannot be used."},"charged":{"type":"boolean","description":"Transcribe and fix failures: whether the cost stayed charged."},"docs":{"type":"string","format":"uri"},"expectedIndex":{"type":"integer","description":"409 from a chunk upload: the index to send next."}},"additionalProperties":true},"Subtitle":{"type":"object","description":"One subtitle file offered by a source, or an AI translation row (`ai: true`).","properties":{"id":{"type":["string","integer"],"description":"Id of the subtitle."},"url":{"type":"string","format":"uri","description":"https://sub.wyzie.io/c/... link carrying `tok`. Each download costs 1 request. AI rows point at /translate."},"flagUrl":{"type":"string","description":"Flag image of the language's locale."},"format":{"type":"string","description":"srt, vtt, ass, ssa, sub..."},"encoding":{"type":"string","description":"Character encoding of the file."},"display":{"type":"string","description":"Language name, capitalised."},"language":{"type":"string","description":"ISO 639-1 code."},"media":{"type":"string","description":"Name of the title."},"isHearingImpaired":{"type":"boolean"},"source":{"type":"string","description":"Source codename (charlie, lima, foxtrot, india, juliet, mike)."},"release":{"type":["string","null"],"description":"Primary release name."},"releases":{"type":"array","items":{"type":"string"},"description":"Other compatible release names."},"origin":{"type":["string","null"],"description":"WEB, BLURAY, DVD..."},"fileName":{"type":["string","null"]},"downloadCount":{"type":["integer","null"],"description":"Downloads on the source, when known."},"matchedRelease":{"type":["string","null"],"description":"The release value that matched your filter."},"matchedFilter":{"type":["string","null"],"description":"The filter that matched."},"ai":{"type":"boolean","description":"true for an AI-translated row (any key but a browser key)."},"match":{"$ref":"#/components/schemas/Match"},"quality":{"$ref":"#/components/schemas/Quality"}},"additionalProperties":true},"Match":{"type":"object","description":"How likely a result fits your `video` / `hash`. Present only when one of them was sent and recognised.","required":["score","reasons"],"properties":{"score":{"type":"integer","minimum":0,"maximum":100},"reasons":{"type":"array","items":{"type":"string"}}}},"Quality":{"type":"object","description":"Score of the file itself, present when it has been scored.","required":["score","flags"],"properties":{"score":{"type":"integer","minimum":0,"maximum":100,"description":"100 minus the flags' penalties."},"flags":{"type":"array","items":{"type":"string","enum":["too_few_cues","overlapping_cues","bad_timing","leftover_ads","wrong_language","machine_translated","encoding_problems","hearing_impaired_tags"]}}}},"SearchBatchRequest":{"type":"object","required":["key","items"],"properties":{"key":{"type":"string"},"items":{"type":"array","minItems":1,"maxItems":50,"items":{"oneOf":[{"type":"string","description":"An IMDB (tt...) or TMDB id."},{"type":"integer","description":"A TMDB id."},{"type":"object","required":["id"],"properties":{"id":{"type":["string","integer"],"description":"IMDB (tt...) or TMDB id."},"season":{"type":"integer","minimum":0},"episode":{"type":"integer","minimum":0},"language":{"type":"string"},"format":{"type":"string"},"hi":{"type":"boolean"},"source":{"type":"string"},"release":{"type":"string"},"filename":{"type":"string"},"origin":{"type":"string"},"video":{"type":"string"},"hash":{"type":"string"},"sort":{"type":"string","enum":["downloads"]},"limit":{"type":"integer","minimum":1,"maximum":200},"best":{"type":"boolean"}},"additionalProperties":false}]}},"language":{"type":"string"},"format":{"type":"string"},"source":{"type":"string"},"hi":{"type":"boolean"},"best":{"type":"boolean","description":"true: each ok item has `subtitle` (object or null) instead of `subtitles`/`count`."}},"additionalProperties":true},"BatchResult":{"type":"object","required":["index","id","ok"],"properties":{"index":{"type":"integer"},"id":{"type":"string"},"season":{"type":"integer"},"episode":{"type":"integer"},"ok":{"type":"boolean"},"count":{"type":"integer"},"subtitles":{"type":"array","items":{"$ref":"#/components/schemas/Subtitle"}},"subtitle":{"oneOf":[{"$ref":"#/components/schemas/Subtitle"},{"type":"null"}],"description":"With best: true."},"status":{"type":"integer","description":"When ok is false: the status /search would have answered."},"error":{"type":"string","description":"When ok is false."}}},"SearchBatchResponse":{"type":"object","required":["cost","results"],"properties":{"cost":{"type":"integer","description":"Requests billed: 1 per item."},"results":{"type":"array","items":{"$ref":"#/components/schemas/BatchResult"}}}},"Track":{"type":"object","required":["index","codec","text"],"properties":{"index":{"type":"integer","description":"Subtitle-stream number, 0-based, in file order."},"codec":{"type":"string","examples":["subrip","hdmv_pgs_subtitle"]},"language":{"type":["string","null"],"description":"3-letter code."},"title":{"type":["string","null"]},"default":{"type":"boolean"},"forced":{"type":"boolean"},"text":{"type":"boolean","description":"false means image-based (PGS, VobSub, DVB), which cannot be turned into text."}}},"ExtractList":{"type":"object","required":["tracks"],"properties":{"tracks":{"type":"array","items":{"$ref":"#/components/schemas/Track"}},"duration":{"type":"number","description":"Seconds."}}},"Usage":{"type":"object","properties":{"key_type":{"type":"string","enum":["paid","free"]},"balance":{"type":"integer","description":"Pro: requests left. Free: left today."},"daily_limit":{"type":["integer","null"],"description":"Free keys: 1000; Pro: null."},"daily_used":{"type":"integer"},"reset_at":{"type":"integer","description":"Unix epoch seconds of the daily reset."},"subscription":{"oneOf":[{"type":"object","properties":{"status":{"type":"string"},"requests_remaining":{"type":"integer"},"requests_total":{"type":"integer"},"current_period_end":{"type":"integer"}}},{"type":"null"}]},"webhook":{"oneOf":[{"$ref":"#/components/schemas/UsageWebhookInfo"},{"type":"null"}]},"since":{"type":"string","format":"date"},"days":{"type":"array","items":{"$ref":"#/components/schemas/UsageDay"}},"totals":{"$ref":"#/components/schemas/UsageTotals"}}},"UsageDay":{"type":"object","properties":{"date":{"type":"string","format":"date"},"requests":{"type":"integer"},"routes":{"$ref":"#/components/schemas/RouteCounts"},"sources":{"type":"object","additionalProperties":{"type":"integer"},"description":"Downloads per source codename."}}},"UsageTotals":{"type":"object","properties":{"requests":{"type":"integer"},"routes":{"$ref":"#/components/schemas/RouteCounts"},"sources":{"type":"object","additionalProperties":{"type":"integer"}}}},"RouteCounts":{"type":"object","description":"Requests per route.","properties":{"search":{"type":"integer"},"download":{"type":"integer"},"dual":{"type":"integer"},"translate":{"type":"integer"},"quote":{"type":"integer"},"sync":{"type":"integer"},"transcribe":{"type":"integer"},"fix":{"type":"integer"},"batch":{"type":"integer"},"extract":{"type":"integer"}},"additionalProperties":{"type":"integer"}},"UsageWebhookInfo":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["balance.low","balance.depleted","limit.reached"]}}}},"UsageWebhookRequest":{"type":"object","required":["key","url"],"properties":{"key":{"type":"string"},"url":{"type":"string","format":"uri","description":"https URL to a public host."}}},"UsageWebhook":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"secret":{"type":"string","description":"whsec_... Signs deliveries; same as the Transcribe webhook secret."},"events":{"type":"array","items":{"type":"string","enum":["balance.low","balance.depleted","limit.reached"]}}}},"QuoteResult":{"type":"object","properties":{"imdbId":{"type":"string"},"title":{"type":["string","null"]},"year":{"type":["integer","null"]},"season":{"type":["integer","null"]},"episode":{"type":["integer","null"]},"language":{"type":"string"},"timeMs":{"type":"integer","description":"Where in the title the line is said."},"line":{"type":"string"},"context":{"type":["string","null"],"description":"The lines around it."},"match":{"type":"string","enum":["phrase","loose"]}}},"SourcesResponse":{"type":"object","required":["sources","free","paid","tiered","allFree"],"properties":{"sources":{"type":"array","items":{"type":"string"},"description":"Live source codenames."},"free":{"type":"array","items":{"type":"string"}},"paid":{"type":"array","items":{"type":"string"}},"tiered":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"tier":{"type":"string","enum":["free","paid"]},"tags":{"type":"array","items":{"type":"string"}},"available":{"type":"boolean","description":"With a key."}}}},"allFree":{"type":"boolean","description":"true when every source is open to every plan."},"key":{"type":"object","description":"With a key.","properties":{"valid":{"type":["boolean","null"]},"type":{"type":"string"},"reason":{"type":"string","description":"malformed, not_found or verification_unavailable."}}},"available":{"type":"array","items":{"type":"string"},"description":"With a valid key."},"restricted":{"type":"array","items":{"type":"string"},"description":"With a valid key."}}},"LanguagesResponse":{"type":"object","required":["translate","count"],"properties":{"translate":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}}}},"count":{"type":"integer"}}},"UptimeWindows":{"type":"object","description":"Percent uptime per window, null when unknown.","properties":{"24h":{"type":["number","null"]},"7d":{"type":["number","null"]},"30d":{"type":["number","null"]},"90d":{"type":["number","null"]}}},"DayUptime":{"type":"object","properties":{"date":{"type":"string","format":"date"},"uptime":{"type":["number","null"]},"downMinutes":{"type":["number","null"]}}},"SourceReport":{"type":"object","properties":{"name":{"type":"string"},"tier":{"type":"string","enum":["free","paid"]},"tags":{"type":"array","items":{"type":"string"}},"status":{"type":"string","description":"The last check's verdict."},"movies":{"type":"string"},"tv":{"type":"string"},"state":{"type":"string","enum":["online","suspect","paused"]},"listed":{"type":"boolean","description":"In /sources and source=all right now."},"pausedSince":{"type":["string","null"],"format":"date-time"},"latencyMs":{"type":["integer","null"]},"lastChecked":{"type":["string","null"],"format":"date-time"},"nextCheck":{"type":["string","null"],"format":"date-time"},"uptime":{"$ref":"#/components/schemas/UptimeWindows"},"history":{"type":"array","items":{"$ref":"#/components/schemas/DayUptime"}}}},"StatusReport":{"type":"object","properties":{"status":{"type":"string","enum":["operational","degraded","partial_outage"]},"summary":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"trackingSince":{"type":["string","null"],"format":"date-time"},"api":{"type":"object","properties":{"status":{"type":"string"},"uptime":{"$ref":"#/components/schemas/UptimeWindows"},"history":{"type":"array","items":{"$ref":"#/components/schemas/DayUptime"}}}},"sources":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SourceReport"}},"incidents":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string"},"start":{"type":"string","format":"date-time"},"end":{"type":["string","null"],"format":"date-time"},"ongoing":{"type":"boolean"},"minutes":{"type":"number"}}}},"docs":{"type":"string","format":"uri"}}},"ShieldsBadge":{"type":"object","properties":{"schemaVersion":{"type":"integer"},"label":{"type":"string"},"message":{"type":"string"},"color":{"type":"string"}}},"SyncRequest":{"type":"object","properties":{"key":{"type":"string"},"url":{"type":"string","description":"A /c/ download link from /search."},"id":{"type":"string","description":"IMDB or TMDB id, with language."},"language":{"type":"string","description":"ISO 639-1, with id."},"season":{"type":"integer"},"episode":{"type":"integer"},"speech":{"type":"array","items":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2},"description":"[[start, end], ...] seconds where people talk."}}},"SyncResponse":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"A /c/ link carrying `offset` and `fps` and a fresh `tok`. Downloading it costs 1 request."},"offset":{"type":"number","description":"Seconds."},"fps":{"type":["string","null"],"description":"SUBTITLE_FPS:VIDEO_FPS, or null."},"confidence":{"type":"number"},"inSync":{"type":"boolean","description":"true when the subtitle already matched your copy."},"subtitle":{"type":"object","additionalProperties":true,"description":"Which subtitle was used (release, fileName, format, source...). With `url`, only its format."},"tried":{"type":"integer","description":"How many candidates were aligned."}}},"SyncUploadSession":{"type":"object","properties":{"uploadId":{"type":"string"},"chunkMaxBytes":{"type":"integer"},"expiresInSeconds":{"type":"integer"}}},"TranscribeFormat":{"type":"string","enum":["srt","vtt","ass","sbv","ttml","txt","json"],"default":"srt"},"TranscribeJson":{"type":"object","description":"format=json. Word-level result; times are seconds. `speaker` only with speakers=1.","properties":{"format":{"type":"string","enum":["json"]},"language":{"type":"string"},"duration":{"type":"number"},"speakers":{"type":"integer","description":"Speakers found (0 otherwise)."},"segments":{"type":"array","items":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"},"text":{"type":"string"},"speaker":{"type":"integer"},"words":{"type":"array","items":{"type":"object","properties":{"word":{"type":"string"},"start":{"type":"number"},"end":{"type":"number"},"speaker":{"type":"integer"}}}}}}},"cues":{"type":"array","items":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"},"text":{"type":"string"}}},"description":"The subtitle cues, grouped as in the srt."}}},"TranscribeJob202":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["processing"]},"charged":{"type":"boolean"},"poll":{"type":"string","format":"uri"},"cost":{"type":"integer"},"duration":{"type":"integer","description":"Seconds of audio."},"webhookSecret":{"type":"string"},"webhook":{"type":"object","additionalProperties":true}}},"FixReport":{"type":"object","description":"report=1.","properties":{"subtitle":{"type":"string"},"changes":{"type":"array","items":{"type":"object","properties":{"start":{"type":"number"},"before":{"type":"string"},"after":{"type":"string"},"kind":{"type":"string"}}}}}},"TranscribeUrlRequest":{"type":"object","required":["key","url"],"properties":{"key":{"type":"string"},"url":{"type":"string","format":"uri"},"format":{"$ref":"#/components/schemas/TranscribeFormat"},"language":{"type":"string"},"translate":{"type":"string"},"speakers":{"type":"boolean"},"sounds":{"type":"boolean"},"cache":{"type":"boolean"},"webhook":{"type":"string","format":"uri"},"dryRun":{"type":"boolean"}}},"TranscribeUrlEstimate":{"type":"object","properties":{"duration":{"type":"number"},"title":{"type":["string","null"]},"estimateRequests":{"type":"integer"}}},"TranscribeUrlJob202":{"type":"object","properties":{"jobId":{"type":"string"},"pollUrl":{"type":"string","format":"uri"},"estimateRequests":{"type":"integer"},"duration":{"type":"number"},"webhookSecret":{"type":"string"}}},"TranscribeUrlProbe":{"type":"object","properties":{"supported":{"type":"boolean"},"duration":{"type":["number","null"]},"title":{"type":["string","null"]},"estimateRequests":{"type":["integer","null"]},"reason":{"type":"string"}}},"TranscribeBatchRequest":{"type":"object","required":["key"],"properties":{"key":{"type":"string"},"feed":{"type":"string","format":"uri","description":"RSS or Atom feed. Exactly one of feed and urls."},"urls":{"type":"array","items":{"type":"string","format":"uri"},"minItems":1,"maxItems":50},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10},"format":{"$ref":"#/components/schemas/TranscribeFormat"},"language":{"type":"string"},"speakers":{"type":"boolean"},"translate":{"type":"string"},"cache":{"type":"boolean"},"webhook":{"type":"string","format":"uri"},"webhookEach":{"type":"boolean"},"dryRun":{"type":"boolean"}}},"TranscribeBatchItem":{"type":"object","properties":{"index":{"type":"integer"},"title":{"type":["string","null"]},"url":{"type":"string"},"status":{"type":"string","enum":["pending","running","done","failed","skipped_no_balance"]},"cost":{"type":"integer"},"duration":{"type":"integer"},"language":{"type":"string"},"cache":{"type":"string"},"error":{"type":"string"},"result":{"type":"string","format":"uri"}}},"BatchEstimate":{"type":"object","properties":{"requests":{"type":"integer"},"minimum":{"type":"boolean","description":"true when some durations were unknown, so the cost is at least this."}}},"TranscribeBatchDryRun":{"type":"object","properties":{"dryRun":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/components/schemas/TranscribeBatchItem"}},"skipped":{"type":"integer"},"estimate":{"$ref":"#/components/schemas/BatchEstimate"}}},"TranscribeBatch202":{"type":"object","properties":{"id":{"type":"string"},"poll":{"type":"string","format":"uri"},"items":{"type":"array","items":{"$ref":"#/components/schemas/TranscribeBatchItem"}},"skipped":{"type":"integer"},"estimate":{"$ref":"#/components/schemas/BatchEstimate"},"webhook":{"type":"object","additionalProperties":true},"webhookSecret":{"type":"string"}}},"TranscribeBatchStatus":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["running","done","stopped"]},"stopped":{"type":"string","enum":["no_balance"]},"source":{"type":"string","enum":["feed","urls"]},"format":{"$ref":"#/components/schemas/TranscribeFormat"},"createdAt":{"type":["string","integer"]},"counts":{"type":"object","additionalProperties":{"type":"integer"}},"requests":{"type":"integer","description":"Requests charged so far."},"zip":{"type":"string","format":"uri"},"items":{"type":"array","items":{"$ref":"#/components/schemas/TranscribeBatchItem"}},"webhook":{"type":"object","additionalProperties":true}}},"TmdbSearchResponse":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"mediaType":{"type":"string","enum":["movie","tv"]},"title":{"type":"string"},"originalTitle":{"type":["string","null"]},"overview":{"type":"string"},"releaseYear":{"type":["string","null"]},"poster":{"type":["string","null"],"format":"uri"},"backdrop":{"type":["string","null"],"format":"uri"},"voteAverage":{"type":["number","null"]},"popularity":{"type":["number","null"]}}}}}},"TmdbTv":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"seasons":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"TmdbSeason":{"type":"object","properties":{"id":{"type":"string"},"season_number":{"type":"integer"},"episodes":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}