> ## Documentation Index
> Fetch the complete documentation index at: https://assemblyai.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompting and Keyterms

Use contextual 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:

* **Contextual prompting** (`prompt`) — a natural-language description of what the audio is about: 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.

## Contextual prompting

Universal-3.5 Pro is trained to use context about the audio — its domain, topic, or scenario — to better recognize 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.

Write the `prompt` as a **description of your audio**, not as instructions to the model. Transcription behavior — punctuation, formatting, verbatim style — is already optimized out of the box, and a managed default prompt is applied when you don't provide one.

* Maximum length: **4096 characters**
* When omitted, a managed default prompt is applied
* `language_code` is **ignored** when a custom `prompt` is set — state the language as part of your description if you need both (see [Specifying the language](#specifying-the-language))

<Tip>
  **Start with no prompt**

  We strongly recommend testing with no `prompt` first. Universal-3.5 Pro is optimized out of the box, and context 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.
</Tip>

### Choosing a level of specificity

Contextual prompts work at three levels of specificity. Use the least specific level that covers your use case, and add detail when your audio contains uncommon names or terms the model can't otherwise know.

| Level        | Length      | What it contains                                            | Example                                                                                                                                                     |
| ------------ | ----------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Domain**   | 2–5 words   | The domain only                                             | `Medical consultation call.`                                                                                                                                |
| **Scenario** | 5–15 words  | What the conversation is about                              | `Cardiology consultation about chest pain symptoms.`                                                                                                        |
| **Detailed** | 20–50 words | Full description, including names, products, or identifiers | `Cardiology consultation between Dr. Smith and an elderly patient regarding recurring chest pain, ECG results, and medication adjustment for hypertension.` |

**Domain context** tells the model what field the audio belongs to — medical, legal, technical support, food ordering. This is the safest starting point and is often enough to fix vocabulary errors.

**Scenario context** describes the specific situation. This is the right level for most applications that know what kind of conversation is taking place — appointment booking, billing inquiry, delivery complaint.

**Detailed context** describes everything your application already knows about the conversation: participant names, account or order identifiers, products, locations. This level is the most powerful when the audio contains proper nouns and identifiers — for example, a voice agent platform that already knows who is calling and why can pass that information so the model spells names and IDs correctly.

Accuracy improves monotonically with context specificity — benchmarked on 20,000 real voice-agent calls, scenario context cuts word error rate \~10% and detailed context \~21% versus no prompt, with the largest gains on names and identifiers. See [Accuracy impact](/docs/streaming/prompting-and-keyterms#accuracy-impact) for the full results.

Guidelines for writing contextual prompts:

* Write plain, complete sentences that describe the audio — you are describing a recording, not commanding the model.
* Include specifics your application already knows — participant names, products, order identifiers — when the audio contains proper nouns the model can't otherwise know.
* Keep it to one short block of text. Don't pack lists of keywords into the prompt — that's what [`keyterms_prompt`](#keyterms-prompting) 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.

### Specifying the language

A custom `prompt` replaces the managed default, including any language steering from `language_code`. When you use a custom prompt with non-English audio, state the language as part of your description:

```
Spanish customer support call about a billing inquiry.
```

For multilingual audio, name all expected languages:

```
Multilingual conversation in English, Spanish, and German.
```

If you don't need a custom prompt, prefer the `language_code` config field — see [Language selection](/docs/sync-stt/language-selection).

<Tabs>
  <Tab title="Python" language="python">
    ```python theme={null}
    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": "Cardiology consultation about chest pain symptoms."}
                ),
                "application/json",
            ),
        },
        timeout=60,
    )
    response.raise_for_status()
    print(response.json()["text"])
    ```
  </Tab>

  <Tab title="JavaScript" language="javascript">
    ```javascript theme={null}
    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: "Cardiology consultation about chest pain symptoms.",
          }),
        ],
        { 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);
    ```
  </Tab>

  <Tab title="cURL" language="bash">
    ```bash theme={null}
    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":"Cardiology consultation about chest pain symptoms."};type=application/json'
    ```
  </Tab>
</Tabs>

## 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 contextual prompting, keyterms biasing is robust to terms that don't end up being spoken, so you can pass your full list with every request.

<Tip>
  **Start with no keyterms**

  **We 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.
</Tip>

**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.

<Tabs>
  <Tab title="Python" language="python">
    ```python theme={null}
    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"])
    ```
  </Tab>

  <Tab title="JavaScript" language="javascript">
    ```javascript theme={null}
    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);
    ```
  </Tab>

  <Tab title="cURL" language="bash">
    ```bash theme={null}
    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'
    ```
  </Tab>
</Tabs>

## Using prompt and keyterms together

You can combine `prompt` and `keyterms_prompt` in the same `config` part, with `prompt` describing the conversation and `keyterms_prompt` enumerating specific terms:

<Tabs>
  <Tab title="Python" language="python">
    ```python theme={null}
    import json
    import requests

    with open("sample.wav", "rb") as f:
        audio = f.read()

    config = {
        "prompt": "Cardiology consultation about chest pain symptoms.",
        "keyterms_prompt": ["Dr. Smith", "ECG", "hypertension"],
    }

    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"])
    ```
  </Tab>

  <Tab title="JavaScript" language="javascript">
    ```javascript theme={null}
    import { readFileSync } from "fs";

    const audio = readFileSync("sample.wav");
    const config = {
      prompt: "Cardiology consultation about chest pain symptoms.",
      keyterms_prompt: ["Dr. Smith", "ECG", "hypertension"],
    };

    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);
    ```
  </Tab>

  <Tab title="cURL" language="bash">
    ```bash theme={null}
    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":"Cardiology consultation about chest pain symptoms.","keyterms_prompt":["Dr. Smith","ECG","hypertension"]};type=application/json'
    ```
  </Tab>
</Tabs>

## Related features

* **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](/docs/sync-stt/conversation-context).
* **Language selection** — steer the default prompt toward one or more languages with `language_code`. See [Language selection](/docs/sync-stt/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)](/docs/streaming/prompting-and-keyterms). For longer pre-recorded audio, see the [Prompting Guide (Async)](/docs/pre-recorded-audio/universal-3-5-pro/prompting).
