Skip to main content

Overview

Send a spoken utterance in a single HTTP call and get back text your user can send as-is: filler gone, self-corrections resolved to what the speaker landed on, punctuation and capitalization applied, and the names and terms they care about spelled the way they spell them. The verbatim transcript always comes back alongside it, so you have both. Cleanup runs by default. With no configuration at all, the cleaned-up text arrives in llm_response and the words exactly as spoken arrive in text. Set llm_instruction when your app needs a particular shape instead, such as a bulleted task list or a clinical note. Dictation runs on Universal-3.5 Pro across 32 languages. The SDK accepts up to 120 seconds of audio per call, and you can start the request before the user stops talking, so most of the utterance is uploaded by the time they finish; see Uploading while recording. For a finished recording of up to 20 minutes, or a compressed format such as MP3, post it to POST /v1/transcribe over HTTP; see Transcribing a finished recording.
Not using the SDK? The same flow works over plain HTTP — see Using the HTTP API directly.
Dictation is a separate service from Sync, Pre-recorded, and Streaming STT. It has its own hostname (dictation.assemblyai.com) and its own request shape. The Python SDK wraps it as DictationTranscriber; in every other language, call it over HTTP.

Before you begin

To complete this guide, you need:
  • An API key — browse to API Keys in your dashboard and copy your key.
  • An audio clip in WAV format, or raw 16-bit PCM. Maximum 120 seconds through the SDK, or 20 minutes over HTTP.
  • Python 3.8+ for the SDK. The HTTP examples lower down need Python 3.8+ with requests or httpx, Node.js 18+ with fetch, or cURL.

Send your first dictation

Step 1: Install the SDK

Step 2: Run your first dictation

Save this as dictate.py, next to a clip.wav file of someone speaking:
Then run it with python dictate.py. You get both versions back from the one call:
text is always what was said, word for word. llm_response is the cleaned-up version your user can send. Nothing had to be configured to get it: cleanup runs by default. transcribe_live() takes a file path, raw audio bytes, or an iterator of audio chunks. That last form is what lets you upload while the user is still speaking, covered in Uploading while recording.

Customize the request

Pass a config to change how the audio is transcribed, or to ask for a different shape of output. Every field is optional, and the SDK takes them as DictationConfig:
Over HTTP the same fields go in the config part of the request body, described in Using the HTTP API directly.

Config parameters

Every field except llm_instruction and rewrite_mode controls transcription. Those two customize the transcript rewrite, which is applied by default — see Rewriting the transcript. Unknown fields are rejected with a 400 rather than ignored, so a typo surfaces as an error instead of a setting that quietly does nothing.

Rewriting the transcript

Cleanup is applied by default. Omitting llm_instruction, or the whole config part, runs the default cleanup task: filler comes out, self-corrections resolve to what the speaker landed on, and punctuation and capitalization are applied. The speaker’s own phrasing and tone survive it. To ask for a different shape instead, set llm_instruction to a plain-English description of the task you want. It replaces the default cleanup task:
The rewrite never replaces the transcription. text is always the verbatim transcript, and the rewritten version arrives separately in llm_response. See Transcript rewriting for how to write a good instruction, what the service enforces for you, and why dictated commands are never carried out.

Uploading while recording

You don’t have to wait for the recording to finish. The endpoint reads the body as it arrives, so you can open the request while the user is still speaking and send audio as it is captured. See Uploading while recording.

What you get back

A successful call returns 200 with JSON:
Rewrites are best-effort. A rewrite failure still returns 200 with the transcription. If llm_response is null and text is present, use text. Never treat a non-null llm_error as a failed request.

Errors

Errors come in two body shapes. Auth failures (401), rate limiting (429), and errors from the transcription step, such as an unknown config field or an unsupported audio format (415), return {"status", "title", "detail"}. Errors Dictation raises itself, such as a malformed request, audio over the limit (413), capacity (503), and upstream failures (502, 504), return {"error", "error_code"}. Read both shapes. Set the HTTP client timeout to 90 seconds. Typical short clips respond in under one second. The rewrite has an internal deadline; past it, the response returns with llm_error: "timeout" and the transcription intact. See Error handling for the full status code table and retry guidance.

Using the HTTP API directly

The SDK wraps a single HTTP request. Call it directly from any language.

Endpoints

Dictation has two transcription endpoints. Choose by whether the audio is still being recorded when you send it: Both return the same response. The rest of this section covers /v1/transcribe/live; see Transcribing a finished recording for /v1/transcribe.
Send the parts in order — config first, then audio. The endpoint reads the body as it arrives, so you can start the request while the user is still speaking and upload the audio as it is captured; see Uploading while recording. /v1/transcribe/stream is the path this endpoint shipped under and still reaches the same handler. There is no unversioned alias.

Authentication

Pass your AssemblyAI API key in the Authorization header as the raw key, with no Bearer prefix:
A missing or invalid API key returns 401 Unauthorized with a {"status", "title", "detail"} body: {"status": 401, "title": "Unauthorized", "detail": "Invalid API key"} when the key is wrong, and "Missing Authorization header" when there is no key at all.

Request body

The body is multipart/form-data with two parts, in this order: Config comes first, and is required, because the server starts transcribing the audio as it arrives and cannot begin without it. An audio part that arrives before config, or a request with no config part at all, is rejected with 400. WAV and raw PCM only. This endpoint decodes audio as it arrives, and compressed formats (MP3, M4A, FLAC, OGG, WebM) cannot be decoded incrementally, so they are rejected with 415. Decode them to WAV or PCM before sending.

Making the request

Transcribing a finished recording

For a recording you already hold in full, post it to /v1/transcribe. It accepts audio from 80 milliseconds up to 20 minutes and 256 MB, and the response is the same as /v1/transcribe/live’s, rewrite included. The server reads the whole body before it starts transcribing, so the request is simpler:
  • config is optional and can come before or after audio. Leave it out to transcribe with defaults, including the default rewrite.
  • Compressed formats are accepted. Set the audio part’s Content-Type to the format: audio/wav, audio/pcm, audio/aac, audio/mpeg (MP3), audio/mp4 (M4A), audio/ogg (Ogg/Opus), audio/flac, or audio/webm. Raw PCM still needs sample_rate and channels in config.
  • Nothing is transcribed until the upload finishes, so for audio that is still being recorded, /v1/transcribe/live returns sooner.
The SDK uses /v1/transcribe/live, so call this endpoint over HTTP. It is also served at /transcribe, without the version prefix.

Next steps