Skip to main content
POST https://api.lokutor.com/v1/speech-to-text transcribes a recording and, when you ask for it, says which speaker said each word. The request and response follow the ElevenLabs Speech to Text (Scribe) shape, so a client written for that API works by changing the base URL and the key.

What it is, honestly

Diarization splits a recording into speakers and numbers them speaker_0, speaker_1, … in order of first appearance.
  • Where it works well: English meetings. On a real 60-minute, 5-person meeting from the AMI corpus it measured a diarization error rate of 8.0%, found 5 of 5 speakers, and attributed 99.4% of words to the right speaker.
  • Where it does not: very short interjections (“yeah”, “mm”) and overlapping speech are missed or given to the wrong speaker.
  • Not yet measured: telephone-quality audio and non-English audio. Treat the speaker labels there as unverified.
Transcription itself is the same recogniser as /stt/transcribe, with greedy decoding (not the language-model beam).

Request

multipart/form-data. Authenticate with xi-api-key: YOUR_KEY, X-API-Key: YOUR_KEY or Authorization: Bearer YOUR_KEY.

Response

  • language_code: ISO-639-3 (eng, spa, …). language_probability is 1.0 when you passed language_code and null when the language was detected.
  • text: the full transcript, formatted.
  • words[].type: word, or spacing for the gap between words.
  • words[].speaker_id: speaker_0 for everything when diarize is false.

Errors

Errors use the ElevenLabs shape, with the HTTP status you would expect:

Limits

  • Audio length for diarize=true: 7,200 seconds (2 hours).
  • File size: 10 MB without diarization; 256 MB with it. Two hours of 16 kHz mono WAV is 219 MB; stereo or 44.1 kHz audio of that length is larger than the limit, so send 16 kHz mono (or cut the file).
  • One diarization request at a time per account. Without diarization the usual concurrency rules apply.
  • Speaker labels run on a GPU that is started for your request. If no diarization has run in the last 10 minutes, the first request waits 5 to 9 minutes (typically 8) for the GPU to start before processing begins; requests that follow within 10 minutes start at once. Processing itself takes about 2.7 minutes for an hour of audio. Keep the connection open and set your client timeout to at least 20 minutes. There is no polling endpoint: the answer arrives on the same connection.

Pricing

Transcription is billed per audio minute at the speech-to-text rate. Speaker labels are a separate line on top: stt_diarization_per_minute per audio minute, with a minimum of stt_diarization_min_minutes audio minutes per request (both on the rate card, GET /v1/pricing). At the current card that is $0.026 per audio minute ($1.56 per hour), billed for at least 60 minutes, so a request is never charged less than $1.56 and a two-hour file is $3.12. The minimum exists because the speaker model runs on a GPU started for your request, which we pay for while it starts and for the ten minutes it waits for the next one; sending several files in a row does not lower the price of each, so send long recordings rather than many short ones. A request that fails, or is answered 503 diarization_busy, is not billed.

Differences from ElevenLabs

  • words[].text is spoken-form (lower case, no punctuation); the top-level text is formatted.
  • No logprob fields.
  • No audio_event entries; tag_audio_events is ignored.
  • language_probability is 1.0 when language_code is given and null when detected (ElevenLabs returns an estimated probability).
  • A word’s end is the frame its last piece was emitted at, so words are short and spacing entries carry the gaps between them.
  • Speakers are numbered by first appearance (speaker_0 is whoever speaks first).
  • Languages: ca de en es eu fr gl it pt only.
  • WAV input only for now.
  • Greedy decoding, not the language-model beam.
  • Not implemented: webhook, cloud_storage_url, additional_formats, entity_detection, keyterms on this route.

Also on /stt/transcribe

POST /v1/stt/transcribe accepts diarize and num_speakers too, and returns Lokutor’s own shape: the usual fields plus turns (consecutive speech by one speaker) and segments, exactly as the recogniser produces them. Same limits and errors (in Lokutor’s error shape).

Attribution

Speaker diarization uses pyannote speaker-diarization-community-1 (pyannote.audio), licensed under CC-BY-4.0. See Licences for the full notice.