Use prompting and keyterms to improve Sync STT transcription accuracy.
The Sync API supports two complementary ways to give the model information about your audio, both passed in the optional config JSON part alongside the audio part:
- Prompting (
prompt) — a custom transcription instruction, optionally including context about the audio: the domain, the scenario, or details of the conversation.
- Keyterms (
keyterms_prompt) — an explicit list of terms you want the model to recognize accurately.
Both improve recognition accuracy for your use case. Neither changes the output format.
Prompting
The prompt field replaces the default transcription instruction with your own. Use it to control transcription behavior — verbatim style, disfluency handling — or to describe the audio so the model better recognizes the vocabulary that context makes likely: a clip described as a cardiology consultation primes the model for medical terminology; one described as an order-status check primes it for order IDs and product names.
- Maximum length: 4096 characters
- When omitted, the default prompt is applied
language_code is ignored when a custom prompt is set — the prompt fully controls the model, so state the language inside the prompt if you need both
Start with no promptWe strongly recommend testing with no prompt first. Universal-3.5 Pro is optimized out of the box, and a custom prompt helps most when your audio contains domain-specific vocabulary the model is getting wrong. Add context when you see those errors, starting with the broadest description that covers your use case.
Guidelines for writing prompts:
- Write plain, complete sentences. A short description of the audio (
Cardiology consultation about chest pain symptoms.) is often enough.
- Include specifics your application already knows — participant names, products, order identifiers — when the audio contains proper nouns the model can’t otherwise know.
- Don’t pack lists of keywords into the prompt — that’s what
keyterms_prompt is for.
- The model stays grounded in the audio: context that turns out to be irrelevant does not cause it to insert words that weren’t spoken, so you can safely send the same description with every request of a longer interaction.
import json
import requests
with open("sample.wav", "rb") as f:
audio = f.read()
response = requests.post(
"https://sync.assemblyai.com/transcribe",
headers={
"Authorization": "<YOUR_API_KEY>",
"X-AAI-Model": "universal-3-5-pro",
},
files={
"audio": ("sample.wav", audio, "audio/wav"),
"config": (
None,
json.dumps({"prompt": "Transcribe verbatim. Preserve disfluencies."}),
"application/json",
),
},
timeout=60,
)
response.raise_for_status()
print(response.json()["text"])
import { readFileSync } from "fs";
const audio = readFileSync("sample.wav");
const form = new FormData();
form.append("audio", new Blob([audio], { type: "audio/wav" }), "sample.wav");
form.append(
"config",
new Blob(
[JSON.stringify({ prompt: "Transcribe verbatim. Preserve disfluencies." })],
{ type: "application/json" }
)
);
const response = await fetch("https://sync.assemblyai.com/transcribe", {
method: "POST",
headers: {
Authorization: "<YOUR_API_KEY>",
"X-AAI-Model": "universal-3-5-pro",
},
body: form,
});
const result = await response.json();
console.log(result.text);
curl -X POST https://sync.assemblyai.com/transcribe \
-H 'Authorization: <YOUR_API_KEY>' \
-H 'X-AAI-Model: universal-3-5-pro' \
-F 'audio=@sample.wav;type=audio/wav' \
-F 'config={"prompt":"Transcribe verbatim. Preserve disfluencies."};type=application/json'
Default prompt
When no prompt is provided, the following default is applied:
Transcribe with context and proper nouns preserved, where speech is present in the audio. Each language as spoken. English as English. Non-native speakers.
Keyterms prompting
The keyterms_prompt field biases the model toward specific tokens — useful for proper nouns, product names, technical jargon, or any term the model might otherwise mishear.
- Value: an array of strings
- Maximum total length: 2048 characters across all terms
- Whitespace is stripped and empty terms are ignored
Keyterms are the right tool when you have an explicit vocabulary list — contact names, product catalogs, medical terms — rather than a description of the conversation. Like prompting, keyterms biasing is robust to terms that don’t end up being spoken, so you can pass your full list with every request.
Start with no keytermsWe strongly recommend starting with no keyterms_prompt and then adding terms as needed based on important words for your use case that you are consistently seeing the model struggle with.Including a large number of terms or common terms that are well represented in the training data could lead to overcorrections and hallucinations.
Best practices:
- Specify unique terminology. Include proper names, company names, technical terms, or vocabulary specific to your domain that might not be commonly recognized.
- Exact spelling and capitalization. Provide keyterms with the precise spelling and capitalization you expect to see in the output transcript.
- Avoid common words. Do not include single, common English words (e.g., “information”) as keyterms. The system is generally proficient with such words, and adding them as keyterms can be redundant.
import json
import requests
with open("sample.wav", "rb") as f:
audio = f.read()
response = requests.post(
"https://sync.assemblyai.com/transcribe",
headers={
"Authorization": "<YOUR_API_KEY>",
"X-AAI-Model": "universal-3-5-pro",
},
files={
"audio": ("sample.wav", audio, "audio/wav"),
"config": (
None,
json.dumps({"keyterms_prompt": ["AssemblyAI", "LeMUR", "U3-Pro"]}),
"application/json",
),
},
timeout=60,
)
response.raise_for_status()
print(response.json()["text"])
import { readFileSync } from "fs";
const audio = readFileSync("sample.wav");
const form = new FormData();
form.append("audio", new Blob([audio], { type: "audio/wav" }), "sample.wav");
form.append(
"config",
new Blob(
[JSON.stringify({ keyterms_prompt: ["AssemblyAI", "LeMUR", "U3-Pro"] })],
{ type: "application/json" }
)
);
const response = await fetch("https://sync.assemblyai.com/transcribe", {
method: "POST",
headers: {
Authorization: "<YOUR_API_KEY>",
"X-AAI-Model": "universal-3-5-pro",
},
body: form,
});
const result = await response.json();
console.log(result.text);
curl -X POST https://sync.assemblyai.com/transcribe \
-H 'Authorization: <YOUR_API_KEY>' \
-H 'X-AAI-Model: universal-3-5-pro' \
-F 'audio=@sample.wav;type=audio/wav' \
-F 'config={"keyterms_prompt":["AssemblyAI","LeMUR","U3-Pro"]};type=application/json'
Using prompt and keyterms together
You can combine prompt and keyterms_prompt in the same config part:
import json
import requests
with open("sample.wav", "rb") as f:
audio = f.read()
config = {
"prompt": "Transcribe verbatim. Preserve disfluencies.",
"keyterms_prompt": ["AssemblyAI", "LeMUR", "U3-Pro"],
}
response = requests.post(
"https://sync.assemblyai.com/transcribe",
headers={
"Authorization": "<YOUR_API_KEY>",
"X-AAI-Model": "universal-3-5-pro",
},
files={
"audio": ("sample.wav", audio, "audio/wav"),
"config": (None, json.dumps(config), "application/json"),
},
timeout=60,
)
response.raise_for_status()
print(response.json()["text"])
import { readFileSync } from "fs";
const audio = readFileSync("sample.wav");
const config = {
prompt: "Transcribe verbatim. Preserve disfluencies.",
keyterms_prompt: ["AssemblyAI", "LeMUR", "U3-Pro"],
};
const form = new FormData();
form.append("audio", new Blob([audio], { type: "audio/wav" }), "sample.wav");
form.append(
"config",
new Blob([JSON.stringify(config)], { type: "application/json" })
);
const response = await fetch("https://sync.assemblyai.com/transcribe", {
method: "POST",
headers: {
Authorization: "<YOUR_API_KEY>",
"X-AAI-Model": "universal-3-5-pro",
},
body: form,
});
const result = await response.json();
console.log(result.text);
curl -X POST https://sync.assemblyai.com/transcribe \
-H 'Authorization: <YOUR_API_KEY>' \
-H 'X-AAI-Model: universal-3-5-pro' \
-F 'audio=@sample.wav;type=audio/wav' \
-F 'config={"prompt":"Transcribe verbatim. Preserve disfluencies.","keyterms_prompt":["AssemblyAI","LeMUR","U3-Pro"]};type=application/json'
- Conversation context — supply the dialogue that preceded the current clip with the
conversation_context field, so the model transcribes multi-turn conversations with better continuity and proper-noun consistency. See Conversation context.
- Language selection — steer the default prompt toward one or more languages with
language_code. See Language selection.
Looking for streaming or async prompting?
This guide covers prompting for Sync STT (short pre-recorded clips). For live audio, see Prompting and keyterms (Real-time). For longer pre-recorded audio, see the Prompting Guide (Async).