Logo of wyzie-docsWyzie Docs

Wyzie Subs

Wyzie Transcribe#

Wyzie Transcribe is a Pro feature: free keys get 403 Paid feature. It costs 6,000 requests per started 30 minutes of audio, so anything shorter than 30 minutes still costs 6,000. Speaker labels cost 60,000 per 30 minutes instead, and translating the result adds a flat 25. The cost is charged when the job starts. A failure on our side is refunded in full, a file with no speech is still charged because recognition ran, and input we refuse before recognition is free.

Wyzie Transcribe writes subtitles for anything with speech in it: podcasts, your own YouTube videos, lectures, interviews, home videos. It doesn't need the title to exist anywhere. You send the audio (or the video), speech recognition writes down every word with its timing, and you get an SRT, WebVTT or ASS file back. The language is detected for you, or you can name it.

On the Web#

The easiest way: open sub.wyzie.io/transcribe, enter your Pro key, pick the file and press Transcribe. Your browser pulls the audio track out of the video first, so only the audio is uploaded (an hour is about 14 MB) and the video itself never leaves your device. MP3, M4A, WAV, MP4, MKV, WebM and most other formats work. Pick a folder to do up to 50 files in one go (see Bulk below).

The API: POST /transcribe#

Send the audio or video file as the request body, with your key in the query string:

curl -X POST "https://sub.wyzie.io/transcribe?key=YOUR_KEY&format=srt" \
  -H "Content-Type: audio/mpeg" --data-binary @podcast.mp3 -o podcast.srt
ParameterExampleDescription
keyYOUR_KEYA Pro API key. Required.
formatsrtsrt (default), vtt or ass.
languageenThe spoken language as a two-letter ISO 639-1 code. Leave it out to detect it from the audio. Required with speakers.
speakers11 to label who is speaking, such as [Speaker 1]. Needs language set to de, en, es, fr, hi, it, ja, nl, pt or ru. Costs 60,000 per 30 minutes.
sounds11 to add sound tags such as [Music] and [Applause] between speech (beta). Costs 100 more per started 30 minutes. It misses some sounds, such as doorbells and door slams. If it fails you still get the transcript and the 100 is refunded. Answers 503 before any charge if the classifier is unavailable. Not available for bulk.
translateSpanishA language to translate the subtitle into, such as Spanish or pt-BR. Adds a flat 25 requests.
webhookhttps://example.com/wyzieAn https URL to call when the job ends. See Webhooks.
cache00 keeps this audio out of the recognition cache: it is neither read from nor written to. See Recognition reuse below.

You can also send a multipart form with the file in a field named media (and key, format, language, speakers, translate as fields), up to 100 MB.

With speakers=1, the speech is recognised by Deepgram Nova-3 instead of Whisper. Each change of speaker starts a new line, and the speaker numbering can reset every 30 minutes in a longer file, so Speaker 1 in the second half is not always the one from the first.

The cost is charged when the job starts. If something fails on our side, all of it is refunded. A file with no speech in it is charged, because recognition ran. Input we refuse before recognition starts, such as a file with no audio track, one that is too long or a bad parameter, is free.

Cloudflare limits a single request to about 100 MB, so for a long video send just the audio track. It is all speech recognition needs:

ffmpeg -i video.mp4 -vn -ac 1 -ar 16000 -b:a 32k audio.mp3

Audio up to 4 hours long is accepted.

Response#

When the transcription finishes within about 50 seconds (most files under 20 minutes), the response is the subtitle file itself, with these headers:

HeaderExampleDescription
x-wyzie-cost6000Requests charged.
x-wyzie-duration1342Length of the audio, in seconds.
x-wyzie-languageenThe language it was transcribed in.
x-wyzie-speakers2How many speakers were found. Only with speakers=1.
x-wyzie-cachemisshit if the recognised text was reused, miss if the audio was recognised now. The price is the same.

A longer file answers 202 Accepted while it keeps working:

{
  "id": "5a29c3f6-4bfb-4f03-b429-4b4d935acdbd",
  "status": "processing",
  "poll": "https://sub.wyzie.io/transcribe/5a29c3f6-4bfb-4f03-b429-4b4d935acdbd",
  "cost": 12000,
  "duration": 2069
}

Poll GET /transcribe/{id}?key=YOUR_KEY every 10 seconds or so. It answers 202 until the subtitle is ready, then the file with the same headers as above. An hour of audio takes about two to three minutes. Only the key that started a transcription can fetch it, and finished subtitles are kept for one hour.

Errors#

StatusMeaning
400A bad format, language or translate value, no file, or speakers without a supported language.
401No key.
402Not enough requests left for this file's length and options.
403A free key, or an invalid one.
413The file is too big (send the audio track only) or longer than 4 hours.
422The file has no audio track or can't be decoded.
429Too many transcriptions from this key this hour (20).
503Busy, or the server restarted while your file was running. Try again; a failed job is refunded in full.

With wyzie-lib#

wyzie-lib's transcribe sends the file and, for a long one, keeps polling until the subtitle is ready. It takes speakers and translate too. It is never retried, because each transcription is billed.

import { transcribe } from 'wyzie-lib';
 
const audio = await fetch('https://example.com/episode-12.mp3').then((r) =>
  r.blob(),
);
const { subtitle, language, duration, cost } = await transcribe({
  media: audio,
  format: 'vtt',
  speakers: true, // optional, needs language
  sounds: true, // optional, beta
  language: 'en',
  translate: 'Spanish', // optional
});

Bulk: Many Files at Once#

On the Transcribe page, pick a folder instead of a file. Up to 50 files are done one after another, and you can download the subtitles one by one or as a zip.

POST /transcribe/batch takes a podcast feed or a list of media links and transcribes each one. Send JSON:

curl -X POST "https://sub.wyzie.io/transcribe/batch" \
  -H "Content-Type: application/json" \
  -d '{"key":"YOUR_KEY","feed":"https://example.com/podcast.rss","limit":10,"format":"srt"}'
FieldExampleDescription
keyYOUR_KEYA Pro API key. Required.
feedhttps://example.com/podcast.rssAn RSS or Atom feed URL. The newest items with audio or video are used. Send feed or urls, not both.
urls["https://example.com/a.mp3"]A list of up to 50 links to audio or video files. Only public http and https links work.
limit10With feed: how many items to take, 1 to 50. Default 10.
optionsspeakers, translateformat, language, speakers and translate work as above and apply to every item.
dryRuntruetrue to list the items and an estimate without starting or charging anything.
webhookhttps://example.com/wyzieAn https URL to call when the job ends. See Webhooks.
webhookEachtruetrue to also call the webhook for every item, not only at the end.
cachefalse0 keeps this audio out of the recognition cache: it is neither read from nor written to. See Recognition reuse below.

The answer is 202 with an id, a poll link, the items and an estimate. Items with no length in the feed are estimated at the minimum, so the real cost can be higher.

{
  "id": "0b7c2f1e-6d0a-4e8a-9a55-3f6f1d7a2c11",
  "poll": "https://sub.wyzie.io/transcribe/batch/0b7c2f1e-6d0a-4e8a-9a55-3f6f1d7a2c11",
  "items": [
    { "index": 0, "title": "Episode 12", "url": "https://example.com/12.mp3", "status": "pending" }
  ],
  "estimate": { "requests": 6000, "minimum": true }
}

A batch costs the sum of its items, each priced like a single transcription. An item is charged when it starts, and a failure on our side is refunded for that item. The first 402 stops the batch: items not yet started are skipped and not charged. A bad link or a file that is not audio fails only its own item, free.

GET /transcribe/batch/{id}?key=YOUR_KEY shows each item's status and cost. GET /transcribe/batch/{id}/zip gives every finished subtitle in one zip, and GET /transcribe/batch/{id}/{n} gives one. Only the key that started the batch can read it, and results are kept for 24 hours.

Recognition Reuse#

We keep the recognised text of audio under a hash of the audio for 30 days. No key, user, job id or file name is attached to it. If anyone sends the same audio again, they get the same text back without a new recognition. The price does not change. Send cache=0 to opt out of both reading and writing. The subtitle itself stays for one hour after the job ends.

Webhooks#

Without a webhook you poll the job link until it is done. With one, we send a signed JSON POST to your server when the job finishes or fails, and you fetch the result with your own key.

Webhooks

Privacy#

The uploaded audio is written to a temporary folder on our server, cut into short pieces, sent for speech recognition (Whisper, run on Cloudflare Workers AI, or Deepgram Nova-3 through Cloudflare when speaker labels are on) and deleted as soon as the transcription ends. It is never logged or used for anything else. The recognised text is kept for 30 days under a hash of the audio, with no key, user, job id or file name (see Recognition reuse), unless you send cache=0. The finished subtitle is kept for one hour so you can fetch it, then deleted. Sound descriptions are detected on our own server, not by a third party.

For a batch, our server fetches the feed and the media links you give it (public addresses only), deletes each file after it is processed, and keeps the finished subtitles for 24 hours. The recognised text is reused like a single file unless you send cache: false. Your API key is held encrypted for up to 24 hours so the batch can keep charging as items start, then deleted with it. A webhook URL, if you gave one, is kept until it has been called, at most a few hours.