Appearance
For clean Markdown of any page, append .md to the page URL. For a complete documentation index, see For full documentation content, see For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at
Transcribe a pre-recorded audio file
Learn how to transcribe and analyze an audio file.
For the complete documentation index, see llms.txt
Important: The speech_models parameter is required for every transcription request. There is no default model. Recommended: ["universal-3-pro", "universal-2"] for broadest language support.
cURL quickstart — transcribe an audio file:
Step 1: Submit a transcription request:
bash
curl \
--header "Authorization: YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"audio_url": "",
"speech_models": ["universal-3-pro", "universal-2"]
}'Step 2: Poll for the result (replace TRANSCRIPT_ID):
bash
curl \
--header "Authorization: YOUR_API_KEY"Poll until status is completed or error. The text field contains the transcript.
To transcribe a local file, first upload it:
bash
curl \
--header "Authorization: YOUR_API_KEY" \
--data-binary @./my-audio.mp3Then use the returned upload_url as the audio_url in the transcription request.
Overview
This guide walks you through transcribing your first audio file with AssemblyAI. You will learn how to submit an audio file for transcription and retrieve the results using the AssemblyAI API.
Building a medical scribe or clinical documentation app? Check out the Medical Scribe guides for post-visit and real-time transcription workflows with Medical Mode, HIPAA-compliant configuration, and SOAP note generation.
When transcribing an audio file, there are three main things you will want to specify:
- The speech models you would like to use (required).
- The region you would like to use (optional).
- Other models you would like to use like Speaker Diarization or PII Redaction (optional).
You must include the speech_models parameter in every transcription request. There is no default model for pre-recorded transcription. If you omit speech_models, the request will fail. See Model selection to learn about available models.
We recommend Universal-3 Pro for pre-recorded audio transcription. It delivers the highest accuracy and fastest transcription out of the box, with optional prompting for when you need more control. For the broadest language coverage (99 languages), use ["universal-3-pro", "universal-2"] to automatically fall back to Universal-2 for unsupported languages.
Prerequisites
Before you begin, make sure you have:
- An AssemblyAI API key (get one by signing up at assemblyai.com)
- Python 3.6 or later installed
- The
requestslibrary (pip install requests)
- An AssemblyAI API key (get one by signing up at assemblyai.com)
- Python 3.8 or later installed
- The
assemblyaipackage (pip install assemblyai)
- An AssemblyAI API key (get one by signing up at assemblyai.com)
- Node.js 18 or later installed
- The
fs-extrapackage (npm install fs-extra)
- An AssemblyAI API key (get one by signing up at assemblyai.com)
- Node.js 18 or later installed
- The
assemblyaipackage (npm install assemblyai)
Step 1: Set up your API credentials
First, configure your API endpoint and authentication:
python
import requests
import time
base_url = ""
headers = {"authorization": "YOUR_API_KEY"}Replace YOUR_API_KEY with your actual AssemblyAI API key.
Use our EU endpoint by changing base_url to "".
python
import assemblyai as aai
aai.settings.base_url = ""
aai.settings.api_key = "YOUR_API_KEY"Replace YOUR_API_KEY with your actual AssemblyAI API key.
Use our EU endpoint by changing base_url to "".
javascript
import fs from "fs-extra";
const baseUrl = "";
const headers = {
authorization: "YOUR_API_KEY",
};Replace YOUR_API_KEY with your actual AssemblyAI API key.
Use our EU endpoint by changing baseUrl to "".
javascript
import { AssemblyAI } from "assemblyai";
const baseUrl = "";
const client = new AssemblyAI({
apiKey: "YOUR_API_KEY",
baseUrl: baseUrl,
});Replace YOUR_API_KEY with your actual AssemblyAI API key.
Use our EU endpoint by changing baseUrl to "".
Step 2: Specify your audio source
You can transcribe audio files in two ways:
Option A: Use a publicly accessible URL
python
audio_file = ""Option B: Upload a local file
If your audio file is stored locally, upload it to AssemblyAI first:
python
with open("./example.mp3", "rb") as f:
response = requests.post(base_url + "/v2/upload", headers=headers, data=f)
if response.status_code != 200:
print(f"Error: {response.status_code}, Response: {response.text}")
response.raise_for_status()
upload_json = response.json()
audio_file = upload_json["upload_url"]Option A: Use a publicly accessible URL
python
audio_file = ""Option B: Use a local file
python
audio_file = "./example.mp3"The SDK handles local file uploads automatically.
Option A: Use a publicly accessible URL
javascript
const audioFile = "";Option B: Upload a local file
If your audio file is stored locally, upload it to AssemblyAI first:
javascript
const audioData = await fs.readFile("./example.mp3");
let res = await fetch(`${baseUrl}/v2/upload`, {
method: "POST",
headers,
body: audioData,
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const uploadResponse = await res.json();
const audioFile = uploadResponse.upload_url;Option A: Use a publicly accessible URL
javascript
const audioFile = "";Option B: Use a local file
javascript
const audioFile = "./example.mp3";The SDK handles local file uploads automatically.
Step 3: Submit the transcription request
Create a request with your audio URL and desired configuration options:
python
data = {
"audio_url": audio_file,
"speech_models": ["universal-3-pro", "universal-2"],
"language_detection": True,
"speaker_labels": True
}
response = requests.post(base_url + "/v2/transcript", headers=headers, json=data)
if response.status_code != 200:
print(f"Error: {response.status_code}, Response: {response.text}")
response.raise_for_status()
transcript_json = response.json()
transcript_id = transcript_json["id"]python
config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
language_detection=True,
speaker_labels=True,
)
transcript = aai.Transcriber().transcribe(audio_file, config=config)javascript
const data = {
audio_url: audioFile,
speech_models: ["universal-3-pro", "universal-2"],
language_detection: true,
speaker_labels: true,
};
let res = await fetch(`${baseUrl}/v2/transcript`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcriptResponse = await res.json();
const transcriptId = transcriptResponse.id;javascript
const params = {
audio: audioFile,
speech_models: ["universal-3-pro", "universal-2"],
language_detection: true,
speaker_labels: true,
};
const transcript = await client.transcripts.transcribe(params);This configuration:
- Uses both the
universal-3-proanduniversal-2models for broad language coverage. Learn more about our different speech recognition models here. - Uses our Automatic Language Detection model to detect the dominant language in the spoken audio.
- Uses our Speaker Diarization model to create turn-by-turn utterances.
The id field returned from POST /v2/transcript is the transcript ID. Persist it (along with a timestamp and the API region) for every transcription request, not just when you hit an error. The transcript ID is required to fetch results, retry, or delete the transcript later — and it's the first thing support@assemblyai.com will ask for when troubleshooting a specific request. See Troubleshoot common errors for the full debugging flow.
Pricing can vary based on the speech model used in the request.
If you already have an account with us, you can find your specific pricing on the Billing page of your dashboard. If you are a new customer, you can find general pricing information here.
Step 4: Poll for the transcription result
Transcription happens asynchronously. Poll the API until the transcription is complete:
python
polling_endpoint = f"{base_url}/v2/transcript/{transcript_id}"
while True:
transcript = requests.get(polling_endpoint, headers=headers).json()
if transcript["status"] == "completed":
print(f"\nFull Transcript:\n\n{transcript['text']}")
break
elif transcript["status"] == "error":
raise RuntimeError(f"Transcription failed: {transcript['error']}")
else:
time.sleep(3)The polling loop checks the transcription status every 3 seconds and prints the full transcript once processing is complete.
The SDK handles polling automatically. Check the result:
python
if transcript.status == aai.TranscriptStatus.error:
raise RuntimeError(f"Transcription failed: {transcript.error}")
print(f"\nFull Transcript:\n\n{transcript.text}")javascript
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
let transcript;
while (true) {
let res = await fetch(pollingEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
transcript = await res.json();
if (transcript.status === "completed") {
console.log(`\nFull Transcript:\n\n${transcript.text}`);
break;
} else if (transcript.status === "error") {
throw new Error(`Transcription failed: ${transcript.error}`);
} else {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}The polling loop checks the transcription status every 3 seconds and prints the full transcript once processing is complete.
The SDK handles polling automatically. Check the result:
javascript
if (transcript.status === "error") {
throw new Error(`Transcription failed: ${transcript.error}`);
}
console.log(`\nFull Transcript:\n\n${transcript.text}`);Step 5: Access speaker diarization (optional)
If you enabled speaker labels, you can access the speaker-separated utterances:
python
for utterance in transcript['utterances']:
print(f"Speaker {utterance['speaker']}: {utterance['text']}")python
for utterance in transcript.utterances:
print(f"Speaker {utterance.speaker}: {utterance.text}")javascript
for (const utterance of transcript.utterances) {
console.log(`Speaker ${utterance.speaker}: ${utterance.text}`);
}javascript
for (const utterance of transcript.utterances) {
console.log(`Speaker ${utterance.speaker}: ${utterance.text}`);
}Complete example
Here is the full working code:
python
import requests
import time
base_url = ""
headers = {"authorization": "YOUR_API_KEY"}
# Use a publicly-accessible URL
audio_file = ""
# Or upload a local file:
# with open("./example.mp3", "rb") as f:
# response = requests.post(base_url + "/v2/upload", headers=headers, data=f)
# if response.status_code != 200:
# print(f"Error: {response.status_code}, Response: {response.text}")
# response.raise_for_status()
# upload_json = response.json()
# audio_file = upload_json["upload_url"]
data = {
"audio_url": audio_file,
"speech_models": ["universal-3-pro", "universal-2"],
"language_detection": True,
"speaker_labels": True
}
response = requests.post(base_url + "/v2/transcript", headers=headers, json=data)
if response.status_code != 200:
print(f"Error: {response.status_code}, Response: {response.text}")
response.raise_for_status()
transcript_json = response.json()
transcript_id = transcript_json["id"]
polling_endpoint = f"{base_url}/v2/transcript/{transcript_id}"
while True:
transcript = requests.get(polling_endpoint, headers=headers).json()
if transcript["status"] == "completed":
print(f"\nFull Transcript:\n\n{transcript['text']}")
# Optionally print speaker diarization results
# for utterance in transcript['utterances']:
# print(f"Speaker {utterance['speaker']}: {utterance['text']}")
break
elif transcript["status"] == "error":
raise RuntimeError(f"Transcription failed: {transcript['error']}")
else:
time.sleep(3)python
import assemblyai as aai
aai.settings.base_url = ""
aai.settings.api_key = "YOUR_API_KEY"
# Use a publicly-accessible URL
audio_file = ""
# Or use a local file:
# audio_file = "./example.mp3"
config = aai.TranscriptionConfig(
speech_models=["universal-3-pro", "universal-2"],
language_detection=True,
speaker_labels=True,
)
transcript = aai.Transcriber().transcribe(audio_file, config=config)
if transcript.status == aai.TranscriptStatus.error:
raise RuntimeError(f"Transcription failed: {transcript.error}")
print(f"\nFull Transcript:\n\n{transcript.text}")
# Optionally print speaker diarization results
# for utterance in transcript.utterances:
# print(f"Speaker {utterance.speaker}: {utterance.text}")javascript
import fs from "fs-extra";
const baseUrl = "";
const headers = {
authorization: "YOUR_API_KEY",
};
async function transcribe() {
// Use a publicly-accessible URL
const audioFile = "";
// Or upload a local file:
// const audioData = await fs.readFile("./example.mp3");
// const uploadRes = await fetch(`${baseUrl}/v2/upload`, {
// method: "POST",
// headers,
// body: audioData,
// });
// if (!uploadRes.ok) throw new Error(`Error: ${uploadRes.status}`);
// const uploadResponse = await uploadRes.json();
// const audioFile = uploadResponse.upload_url;
const data = {
audio_url: audioFile,
speech_models: ["universal-3-pro", "universal-2"],
language_detection: true,
speaker_labels: true,
};
let res = await fetch(`${baseUrl}/v2/transcript`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcriptResponse = await res.json();
const transcriptId = transcriptResponse.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
while (true) {
res = await fetch(pollingEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcript = await res.json();
if (transcript.status === "completed") {
console.log(`\nFull Transcript:\n\n${transcript.text}`);
// Optionally print speaker diarization results
// for (const utterance of transcript.utterances) {
// console.log(`Speaker ${utterance.speaker}: ${utterance.text}`);
// }
break;
} else if (transcript.status === "error") {
throw new Error(`Transcription failed: ${transcript.error}`);
} else {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
}
transcribe();javascript
import { AssemblyAI } from "assemblyai";
const baseUrl = "";
const client = new AssemblyAI({
apiKey: "YOUR_API_KEY",
baseUrl: baseUrl,
});
// Use a publicly-accessible URL
const audioFile = "";
// Or use a local file:
// const audioFile = "./example.mp3";
const params = {
audio: audioFile,
speech_models: ["universal-3-pro", "universal-2"],
language_detection: true,
speaker_labels: true,
};
const run = async () => {
const transcript = await client.transcripts.transcribe(params);
if (transcript.status === "error") {
throw new Error(`Transcription failed: ${transcript.error}`);
}
console.log(`\nFull Transcript:\n\n${transcript.text}`);
// Optionally print speaker diarization results
// for (const utterance of transcript.utterances) {
// console.log(`Speaker ${utterance.speaker}: ${utterance.text}`);
// }
};
run();Next steps
Now that you have transcribed your first audio file:
- Learn how you can do even more with Universal-3 Pro with prompting
- Explore our Speech Understanding features for more ways to analyze your audio data
- Learn more about searching, summarizing, or asking questions on your transcript with our LLM Gateway feature
- Find out how to use webhooks to get notified when your transcripts are ready
For more information, check out the full API reference documentation.