Send a file, get a transcript. POST /v1/audio/transcriptions takes a multipart upload and answers with the words in it. Before you start: put a key in EESI_API_KEY — see Authentication — and install a client if you want one, from SDKs. Neither SDK is published to PyPI or npm yet, so both install from a checkout.
The SDK defaults are sized for JSON calls, not for a GPU pass over an hour of audio. Anything past a couple of minutes of recording needs a longer budget.In Python, pass EESIClient(timeout=1800). A float covers every phase.TypeScript has two budgets, and the one a long decode hits is not the one named “read”. connectTimeoutMs (10 s by default) bounds the wait for response headers; readTimeoutMs (60 s) bounds reading the body once they arrive. The gateway sends no headers until the model has answered, so new EESIClient({ readTimeoutMs: 1_800_000 }) on its own still gives up after ten seconds with RequestTimeoutError: POST /audio/transcriptions timed out (connect after 10000 ms). Pass new EESIClient({ connectTimeoutMs: 1_800_000, readTimeoutMs: 1_800_000 }).Either way the GPU carries on with the work after your side has stopped waiting for it.

Is this the right endpoint

A recording you already have

Calls, voicemails, uploads, anything that is a file rather than a stream. This endpoint.

Captions and search

verbose_json carries the timings you need to line text up with audio. This endpoint.

Several speakers

Use audio intelligence — the same endpoint and the same model, asked for verbose_json, which adds speaker labels.

A live microphone

Use a realtime session. It streams, and it decides where turns end.
Do not chop a live microphone into repeated POSTs. It costs a round trip per chunk, and it cuts turns at arbitrary boundaries rather than where somebody stopped talking — which is the difference between a transcript you can read and a wall of fragments.

The request

Everything is a form field on a multipart/form-data body.

What each response_format gives you

srt and vtt are in the request schema, and no transcription backend in this catalog serves them. Sending either reaches the model and comes back as a relayed 400: response_format 'srt' is not supported. Supported: json, text, verbose_json. Ask for verbose_json and build the caption file from segments — you need the timings anyway.

Pass language when you know it

Auto-detection is decided from the opening seconds. A recording that starts with noise, hold music, or a greeting in a different language can be identified wrongly, and once it is, the entire transcript comes back in the wrong language. That failure is total rather than partial, which is what makes the hint worth sending even when detection is usually right.
A supplied language is echoed back untouched. When you omit it, the response carries the detected code and a language_probability beside it.

Timings and segments

verbose_json is what lets you line a transcript up with the audio it came from — build captions, jump a player to a phrase, or index a recording for search.
Transcription is one diarizing model, so verbose_json carries speaker and the acoustic fields even when you asked for plain transcription. They are part of what nur-stt-v1 is, not a tier you upgrade into. Skip the word-alignment pass with timestamp_granularities[]=segment. On a long file that is worth a few seconds of GPU time.

Streaming a long decode

A long recording decodes for minutes. stream=true turns the response into server-sent events so you can show progress rather than a spinner:
The frames are transcript.text.delta as text accumulates, transcript.segment per finished segment, and one transcript.text.done carrying the whole verbose_json payload in a verbose field — so a streaming client never needs a second request for the authoritative result. Each segment’s end is how far into the audio the model has reached, which makes a progress bar end / duration. A model whose backend cannot stream still honours stream=true: the batch call runs and the finished transcript arrives as one transcript.text.delta followed by transcript.text.done. You get the contract, not the progress.

Limits and cost

Uploads are read in chunks and refused as soon as they cross the cap, so an oversized file is rejected rather than buffered. The message names the cap and what to do about it. Billing follows the audio, not the request: json and verbose_json are metered on the duration the model reports, and text on the duration measured from the file you sent. A client that hangs up mid-stream is still billed, because the decode was already spent.

Failures

One mistake, three statuses. A model id that does not work here answers 404 when nothing in the catalog has it, 400 when it is real but belongs to another endpoint, and 503 when it is the right kind and this deployment has no backend for it. The last is a deployment fact rather than a mistake in your request, which is why it is not a 4xx.

Next

Audio intelligence

Speakers, word timing and audibility from the same endpoint.

Transcribe a meeting

The whole recipe, including naming the speakers.

Live conversation

A microphone rather than a file.

Models

Which id serves what, and how to read the catalog.

Authentication

Where an sk-eesi-… key comes from, and what a bad one looks like.