Skip to content

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

Model selection ​

For the complete documentation index, see llms.txt

Key parameter: speech_models (required, array of strings). There is no default model. Available models: universal-3-pro (highest accuracy, fastest, 6 languages), universal-2 (99 languages, cost-effective). Recommended: ["universal-3-pro", "universal-2"] — uses U3 Pro where supported, falls back to U2 for other languages. After transcription, check speech_model_used to see which model was actually used.

cURL quickstart:

bash
curl  \
  --header "Authorization: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "audio_url": "",
    "speech_models": ["universal-3-pro", "universal-2"],
    "language_detection": true
  }'

The speech_models parameter lets you specify which model to use for transcription. You can provide multiple models in priority order, and our system will automatically route to the best available model based on your request.

You must include the speech_models parameter in every pre-recorded transcription request. There is no default model. If you omit speech_models, the request will fail.

Model routing behavior: The system attempts to use the models in priority order falling back to the next model when needed. For example, with ["universal-3-pro", "universal-2"], the system will try to use universal-3-pro for languages it supports (English, Spanish, Portuguese, French, German, and Italian), and automatically fall back to Universal for all other languages. This ensures you get the best performing transcription where available while maintaining the widest language coverage.

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.

NameParameterDescriptionBest for
Universal-3 Prospeech_models=['universal-3-pro']Our highest accuracy, fastest model. Works great out of the box, with optional prompting for more control.Highest-accuracy transcription, post-call analytics, meeting notetakers, medical transcription, domain-specific accuracy via prompting
Universal-2speech_models=['universal-2']Our accurate, cost-effective model with support across 99 languages.High-volume batch transcription, 99-language coverage, price-sensitive workloads, fallback for unsupported U3 Pro languages
NameParameterDescriptionBest for
Universal-3 Prospeech_models: ['universal-3-pro']Our highest accuracy, fastest model. Works great out of the box, with optional prompting for more control.Highest-accuracy transcription, post-call analytics, meeting notetakers, medical transcription, domain-specific accuracy via prompting
Universal-2speech_models: ['universal-2']Our accurate, cost-effective model with support across 99 languages.High-volume batch transcription, 99-language coverage, price-sensitive workloads, fallback for unsupported U3 Pro languages
NameAPI ParameterDescriptionBest for
Universal-3 Pro"speech_models": ["universal-3-pro"]Our highest accuracy, fastest model. Works great out of the box, with optional prompting for more control.Highest-accuracy transcription, post-call analytics, meeting notetakers, medical transcription, domain-specific accuracy via prompting
Universal-2"speech_models":["universal-2"]Our accurate, cost-effective model with support across 99 languages.High-volume batch transcription, 99-language coverage, price-sensitive workloads, fallback for unsupported U3 Pro languages

Quickstart ​

You can change the model by setting the speech_models in the POST request body:

python
import requests
import time

base_url = ""

headers = {
    "authorization": "<YOUR_API_KEY>"
}

data = {
    "audio_url": "",
    "speech_models": ["universal-3-pro", "universal-2"],
    "language_detection": True
}

url = base_url + "/v2/transcript"
response = requests.post(url, json=data, headers=headers)

transcript_id = response.json()['id']
polling_endpoint = base_url + "/v2/transcript/" + transcript_id

while True:
  transcription_result = requests.get(polling_endpoint, headers=headers).json()

  if transcription_result['status'] == 'completed':
    print(transcription_result['text'])
    break

  elif transcription_result['status'] == 'error':
    raise RuntimeError(f"Transcription failed: {transcription_result['error']}")

  else:
    time.sleep(3)

You can change the model by setting speech_models in the transcription config:

python
import assemblyai as aai

aai.settings.api_key = "<YOUR_API_KEY>"

audio_file = ""

config = aai.TranscriptionConfig(
    speech_models=["universal-3-pro", "universal-2"],
    language_detection=True
)
transcript = aai.Transcriber(config=config).transcribe(audio_file)

if transcript.status == aai.TranscriptStatus.error:
  raise RuntimeError(f"Transcription failed: {transcript.error}")

print(transcript.text)

You can change the model by setting the speech_models in the POST request body:

javascript
const baseUrl = "";

const headers = {
  authorization: "<YOUR_API_KEY>",
};

const data = {
  audio_url: "",
  speech_models: ["universal-3-pro", "universal-2"],
  language_detection: true,
};

const url = `${baseUrl}/v2/transcript`;
let res = await fetch(url, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();

const transcriptId = response.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;

while (true) {
  res = await fetch(pollingEndpoint, { headers });
  if (!res.ok) throw new Error(`Error: ${res.status}`);
  const transcriptionResult = await res.json();

  if (transcriptionResult.status === "completed") {
    console.log(transcriptionResult.text);
    break;
  } else if (transcriptionResult.status === "error") {
    throw new Error(`Transcription failed: ${transcriptionResult.error}`);
  } else {
    await new Promise((resolve) => setTimeout(resolve, 3000));
  }
}

You can change the model by setting the speech_models in the transcript parameters:

javascript
import { AssemblyAI } from "assemblyai";

const client = new AssemblyAI({
  apiKey: "<YOUR_API_KEY>",
});

const audioFile = "";

const params = {
  audio: audioFile,
  speech_models: ["universal-3-pro", "universal-2"],
  language_detection: true,
};

const run = async () => {
  const transcript = await client.transcripts.transcribe(params);

  if (transcript.status === "error") {
    throw new Error(`Transcription failed: ${transcript.error}`);
  }

  console.log(transcript.text);
};

run();

Identify the model used ​

After transcription completes, you can check which model was actually used to process your request by reading the speech_model_used field. This is useful when you provide multiple models in the speech_models array, as the system may fall back to a different model depending on language support.

python
import requests
import time

base_url = ""

headers = {
    "authorization": "<YOUR_API_KEY>"
}

data = {
    "audio_url": "",
    "speech_models": ["universal-3-pro", "universal-2"],
    "language_detection": True
}

url = base_url + "/v2/transcript"
response = requests.post(url, json=data, headers=headers)

transcript_id = response.json()['id']
polling_endpoint = base_url + "/v2/transcript/" + transcript_id

while True:
  transcription_result = requests.get(polling_endpoint, headers=headers).json()

  if transcription_result['status'] == 'completed':
    print(f"Model used: {transcription_result['speech_model_used']}")
    print(transcription_result['text'])
    break

  elif transcription_result['status'] == 'error':
    raise RuntimeError(f"Transcription failed: {transcription_result['error']}")

  else:
    time.sleep(3)
python
import assemblyai as aai

aai.settings.api_key = "<YOUR_API_KEY>"

audio_file = ""

config = aai.TranscriptionConfig(
    speech_models=["universal-3-pro", "universal-2"],
    language_detection=True
)
transcript = aai.Transcriber(config=config).transcribe(audio_file)

if transcript.status == aai.TranscriptStatus.error:
    raise RuntimeError(f"Transcription failed: {transcript.error}")

print(f"Model used: {transcript.json_response['speech_model_used']}")
print(transcript.text)
javascript
const baseUrl = "";

const headers = {
  authorization: "<YOUR_API_KEY>",
};

const data = {
  audio_url: "",
  speech_models: ["universal-3-pro", "universal-2"],
  language_detection: true,
};

const url = `${baseUrl}/v2/transcript`;
let res = await fetch(url, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();

const transcriptId = response.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;

while (true) {
  res = await fetch(pollingEndpoint, { headers });
  if (!res.ok) throw new Error(`Error: ${res.status}`);
  const transcriptionResult = await res.json();

  if (transcriptionResult.status === "completed") {
    console.log(`Model used: ${transcriptionResult.speech_model_used}`);
    console.log(transcriptionResult.text);
    break;
  } else if (transcriptionResult.status === "error") {
    throw new Error(`Transcription failed: ${transcriptionResult.error}`);
  } else {
    await new Promise((resolve) => setTimeout(resolve, 3000));
  }
}
javascript
import { AssemblyAI } from "assemblyai";

const client = new AssemblyAI({
  apiKey: "<YOUR_API_KEY>",
});

const audioFile = "";

const params = {
  audio: audioFile,
  speech_models: ["universal-3-pro", "universal-2"],
  language_detection: true,
};

const run = async () => {
  const transcript = await client.transcripts.transcribe(params);

  if (transcript.status === "error") {
    throw new Error(`Transcription failed: ${transcript.error}`);
  }

  console.log(`Model used: ${transcript.speech_model_used}`);
  console.log(transcript.text);
};

run();

Complete example ​

Here is the full working code that demonstrates model selection with error handling:

python
import requests
import time

base_url = ""
headers = {"authorization": "<YOUR_API_KEY>"}

data = {
    "audio_url": "",
    "speech_models": ["universal-3-pro", "universal-2"],
    "language_detection": 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"Model used: {transcript['speech_model_used']}")
        print(f"\nTranscript:\n\n{transcript['text']}")
        break
    elif transcript["status"] == "error":
        raise RuntimeError(f"Transcription failed: {transcript['error']}")
    else:
        time.sleep(3)
python
import assemblyai as aai

aai.settings.api_key = "<YOUR_API_KEY>"

audio_file = ""

config = aai.TranscriptionConfig(
    speech_models=["universal-3-pro", "universal-2"],
    language_detection=True,
)

transcript = aai.Transcriber(config=config).transcribe(audio_file)

if transcript.status == aai.TranscriptStatus.error:
    raise RuntimeError(f"Transcription failed: {transcript.error}")

print(f"Model used: {transcript.json_response['speech_model_used']}")
print(f"\nTranscript:\n\n{transcript.text}")
javascript
const baseUrl = "";

const headers = {
  authorization: "<YOUR_API_KEY>",
};

async function transcribe() {
  const audioFile = "";

  const data = {
    audio_url: audioFile,
    speech_models: ["universal-3-pro", "universal-2"],
    language_detection: 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(`Model used: ${transcript.speech_model_used}`);
      console.log(`\nTranscript:\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));
    }
  }
}

transcribe();
javascript
import { AssemblyAI } from "assemblyai";

const client = new AssemblyAI({
  apiKey: "<YOUR_API_KEY>",
});

const audioFile = "";

const params = {
  audio: audioFile,
  speech_models: ["universal-3-pro", "universal-2"],
  language_detection: true,
};

const run = async () => {
  const transcript = await client.transcripts.transcribe(params);

  if (transcript.status === "error") {
    throw new Error(`Transcription failed: ${transcript.error}`);
  }

  console.log(`Model used: ${transcript.speech_model_used}`);
  console.log(`\nTranscript:\n\n${transcript.text}`);
};

run();