> This page is for Audio Decisions.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://dev.hume.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://dev.hume.ai/_mcp/server.

# For coding agents

**This page gives a coding agent what it needs to build with the Audio Decisions API: what the API does, one complete request and response, and the rules that code most often gets wrong.** Point your agent to this page before it writes code that calls the API.

## Set up your agent

Add this to your project's agent instructions, such as `CLAUDE.md` or `AGENTS.md`:

#### Agent instructions

```markdown wordWrap showLineNumbers={false}
Before writing code that calls the Audio Decisions API, read https://dev.hume.ai/audio-decisions/docs/for-coding-agents.md. For any other Audio Decisions page, find it in https://dev.hume.ai/audio-decisions/llms.txt and fetch its Markdown by adding .md to the page URL.
```

<table>
  <thead>
    <tr>
      <th width="25%">
        Resource
      </th>

      <th>
        Use
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        Markdown pages
      </td>

      <td>
        Add 

        `.md`

         to the URL of any page, such as 

        `https://dev.hume.ai/audio-decisions/docs/for-coding-agents.md`

        .
      </td>
    </tr>

    <tr>
      <td>
        `llms.txt`
      </td>

      <td>
        `https://dev.hume.ai/audio-decisions/llms.txt`

         lists every Audio Decisions page with a one-line description.
      </td>
    </tr>

    <tr>
      <td>
        MCP server
      </td>

      <td>
        `https://dev.hume.ai/_mcp/server`

         gives an MCP client a tool that searches all of dev.hume.ai and returns an answer with links to its sources. Fetch a cited page's 

        `.md`

         for exact field names and request shapes. In Claude Code, run 

        `claude mcp add --transport http hume-docs https://dev.hume.ai/_mcp/server`

        .
      </td>
    </tr>

    <tr>
      <td>
        Agent skill
      </td>

      <td>
        [HumeAI/hume-audio-decisions-skills](https://github.com/HumeAI/hume-audio-decisions-skills)

         contains a skill your agent loads when it works with this API. It covers choosing which audio to send, writing and breaking down questions, and reading answers. In Claude Code, copy its 

        `audio-decisions-api`

         folder into your project's 

        `.claude/skills/`

         folder.
      </td>
    </tr>
  </tbody>
</table>

## What the API does

1. **A request sends one audio file and your questions about it, written in plain language.** All the questions in a request are answered in one model inference.
2. **Each answer is numbers, not text.** A `noul`, `choice` or `score` answer gives probabilities that estimate the share of human raters who would give each answer. A `span` answer gives the times where an event may occur. There is no transcript, reply or explanation, so the calling code makes the decision.
3. **The API is HTTP only, with one file per request.** To evaluate many recordings, send one request per file. To evaluate live audio, send short clips as they are captured.

## Make a request

A request is a `multipart/form-data` `POST` to `https://api.cloud.hume.ai/v0/decisions/file`, with the API key in the `X-Hume-Api-Key` header and two parts, sent in this order:

1. `request`: a JSON object with `questions`, each keyed by an ID you choose, and an optional `context` string that describes the recording.
2. `file`: one audio file, MP3 or WAV.

#### cURL

```bash maxLines={0}
curl https://api.cloud.hume.ai/v0/decisions/file \
  -H "X-Hume-Api-Key: $HUME_API_KEY" \
  -F 'request={
    "context": "A simulated test call in which a voice AI agent helps a caller reschedule an appointment. Both voices are synthetic, and the agent speaks first.",
    "questions": {
      "talks_over_caller": {
        "type": "noul",
        "instructions": "Does the agent talk over the caller?"
      },
      "agent_naturalness": {
        "type": "score",
        "instructions": "How natural does the agent sound?",
        "criteria": ["Not at all", "2", "3", "4", "Extremely"]
      }
    }
  };type=application/json' \
  -F file=@test_call.wav
```

#### Python

```python maxLines={0}
from hume_audio_decisions import (
    DecisionsClient,
    DecisionsRequest,
    Question_Noul,
    Question_Score,
)

client = DecisionsClient()

request = DecisionsRequest(
    context=(
        "A simulated test call in which a voice AI agent helps a "
        "caller reschedule an appointment. Both voices are "
        "synthetic, and the agent speaks first."
    ),
    questions={
        "talks_over_caller": Question_Noul(
            instructions="Does the agent talk over the caller?",
        ),
        "agent_naturalness": Question_Score(
            instructions="How natural does the agent sound?",
            criteria=["Not at all", "2", "3", "4", "Extremely"],
        ),
    },
)

with open("test_call.wav", "rb") as audio:
    response = client.decisions.create(
        file=("test_call.wav", audio, "audio/wav"),
        request=request,
    )

print(response.model_dump_json(indent=2))
```

#### TypeScript

```typescript maxLines={0}
import { DecisionsClient } from "@humeai/audio-decisions";

const client = new DecisionsClient();

const response = await client.decisions.create({
  file: {
    path: "test_call.wav",
    contentType: "audio/wav",
  },
  request: {
    context:
      "A simulated test call in which a voice AI agent helps a " +
      "caller reschedule an appointment. Both voices are " +
      "synthetic, and the agent speaks first.",
    questions: {
      talks_over_caller: {
        type: "noul",
        instructions: "Does the agent talk over the caller?",
      },
      agent_naturalness: {
        type: "score",
        instructions: "How natural does the agent sound?",
        criteria: ["Not at all", "2", "3", "4", "Extremely"],
      },
    },
  },
});

console.log(JSON.stringify(response, null, 2));
```

The response keys each answer by the ID of its question. It also carries the `run_id` of the model run, and `received`, which holds the input tokens the request is billed:

#### 200 OK

```json
{
  "run_id": "019a1f3c-7d2e-7b41-9c58-2e6f4a1d8b03",
  "answers": {
    "talks_over_caller": {
      "type": "noul",
      "noul": 0.1274
    },
    "agent_naturalness": {
      "type": "score",
      "score": 2.7195,
      "confidence": 0.4229,
      "probabilities": {
        "0": 0.0218,
        "1": 0.0874,
        "2": 0.2463,
        "3": 0.4385,
        "4": 0.206
      },
      "legend": {
        "0": "Not at all",
        "1": "2",
        "2": "3",
        "3": "4",
        "4": "Extremely"
      }
    }
  },
  "received": {
    "input_tokens": 11234
  }
}
```

<table>
  <thead>
    <tr>
      <th width="20%">
        SDK
      </th>

      <th>
        Package
      </th>

      <th>
        Client
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        Python
      </td>

      <td>
        `hume-audio-decisions`

        , imported as 

        `hume_audio_decisions`
      </td>

      <td>
        `DecisionsClient()`

         reads the key from 

        `HUME_API_KEY`

        . Each primitive has its own question class, such as 

        `Question_Noul`

        .
      </td>
    </tr>

    <tr>
      <td>
        TypeScript
      </td>

      <td>
        `@humeai/audio-decisions`
      </td>

      <td>
        `new DecisionsClient()`

         reads the key from 

        `HUME_API_KEY`

        . Questions are plain objects with a 

        `type`

         field.
      </td>
    </tr>
  </tbody>
</table>

## Question types

Each question's `type` names its primitive, which sets the `criteria` it takes and the fields of its answer. One request can mix types.

<table>
  <thead>
    <tr>
      <th width="13%">
        Type
      </th>

      <th>
        Asks
      </th>

      <th>
        `criteria`
      </th>

      <th>
        Answer fields
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        [`noul`](/audio-decisions/docs/primitives#noul)
      </td>

      <td>
        Whether something is true of the audio.
      </td>

      <td>
        Optional object with 

        `true`

         and 

        `false`

         strings.
      </td>

      <td>
        `noul`

        , the share of raters who would answer yes.
      </td>
    </tr>

    <tr>
      <td>
        [`choice`](/audio-decisions/docs/primitives#choice)
      </td>

      <td>
        Which of several unordered options applies.
      </td>

      <td>
        Array of objects, each with a unique 

        `name`

         and an optional 

        `description`

        .
      </td>

      <td>
        `choice`

        , 

        `confidence`

         and 

        `probabilities`

         keyed by option name.
      </td>
    </tr>

    <tr>
      <td>
        [`score`](/audio-decisions/docs/primitives#score)
      </td>

      <td>
        Where the audio falls on an ordered scale.
      </td>

      <td>
        Array of unique level strings, lowest first.
      </td>

      <td>
        `score`

        , 

        `confidence`

        , 

        `probabilities`

         and 

        `legend`

        , the last two keyed by level index.
      </td>
    </tr>

    <tr>
      <td>
        [`span`](/audio-decisions/docs/primitives#span)
      </td>

      <td>
        When an event occurs. This primitive is experimental and most reliable for vocal bursts and sound events. Its question and answer formats are stable.
      </td>

      <td>
        None.
      </td>

      <td>
        `spans`

        , each with 

        `audio_start_ms`

        , 

        `audio_end_ms`

         and 

        `probability`

        .
      </td>
    </tr>
  </tbody>
</table>

## Rules for calling code

### Questions

1. **Ask each question for one judgment a listener could make from the audio, and combine the answers in code.** For a broad decision such as "Did the agent handle the call well?", ask about the agent's tone, the caller's frustration and whether the caller asks to cancel, then combine those answers. If a person listening to the audio would find a question hard to answer, the model is likely to find it hard too.
2. **List the possible answers instead of asking an open question.** Answers are probabilities over the options you give, or time spans. To find why someone called, ask a `choice` question that lists the reasons.
3. **Give every `choice` question a neutral option and an option for audio that fits none of the others.** Add "neutral" to emotions such as angry, fearful and sad, "unsure" to yes and no, and "none of these" to any list that might not cover every recording.
4. **Make `choice` options distinct categories, not narrow number ranges.** Ask for "slow", "normal" or "fast" rather than ranges of words per minute.
5. **Expect `span` answers to be most reliable for vocal bursts and sound events**, such as laughs, sighs, coughs or a phone ringing. For other events, such as a word being spoken, check the spans against audio where you know the answer before relying on them.
6. **Do not ask questions that need musical understanding**, such as where the chorus starts. See [Questions the model does not answer well](/audio-decisions/docs/writing-questions#questions-the-model-does-not-answer-well).
7. **Send the same questions in the same order for every recording you compare.** An answer can change when other questions in the request are added, removed or reordered, so a threshold holds only for the request it was set on.
8. **Put the text a question depends on in `context`**, such as a script or the requested speaking style. Every question in a request shares one `context`, so questions that need different context go in separate requests.
9. **Name the speaker a question is about**, such as "the agent" or "the caller", and describe each speaker in `context`.

### Answers

1. **A probability is the estimated share of raters, not the model's certainty.** A `noul` of 0.5 means raters would split, and a `noul` of 0.6 means 60% would answer yes, not "somewhat yes".
2. **Read `score` levels through `legend`.** Level indices start at 0, so on a scale labeled "Not at all", "2", "3", "4", "Extremely", index 1 is the level labeled "2". `score` is the mean level index, not a label.
3. **Choose thresholds from labeled audio.** The API sets no threshold. Compare answers with the known answers for recordings of the kind you will judge.
4. **Send each request once.** The same request with the same file returns the same answers, so averaging repeats adds nothing. Answers can change when the model is updated.
5. **Store each answer with its `run_id` and the questions that produced it.** The run endpoints return a run's status and request, but not its answers.

### Audio

1. **Send the whole conversation as one file, and name the speaker each question is about.** To judge one person apart from the others, send that person's audio as its own file. The model hears audio as one channel at 16 kHz and does not hear which side or channel a sound comes from.
2. **Send 5 seconds to 5 minutes of audio, in a request body of at most 25,000,000 bytes.** Shorter audio is rejected with `audio_too_short` and longer audio with `audio_too_long`. Split long recordings into one request per part, and convert large WAV files to 16 kHz mono, since a higher sample rate or a second channel does not improve answers. See [Limits](/audio-decisions/docs/limits).
3. **Skip silent or nearly silent files.** The model can answer silence with high confidence.

### Requests and errors

1. **Keep the API key on a server you control.** To use the API from a browser, relay the audio through your server.
2. **Send only documented fields.** Requests are validated strictly and an unrecognized field is rejected. In responses, ignore unrecognized fields, and treat an answer with an unrecognized `type` as unknown rather than as an error.
3. **Branch on the error's `code`, and on the status when there is no `code`.** The gateway's `401`, `429` and `404` for a path or method the API does not serve carry no `code`.
4. **Retry `429` and `503` after the seconds in the `Retry-After` header, and retry `500`.** Both SDKs do this, retrying a request twice. Fix a `400`, `413` or `415` before resending, since the same request fails again. The rate limit is 60 requests per minute, shared by every API key in the organization. See [Errors](/audio-decisions/docs/errors).

## Where to go next

<table>
  <thead>
    <tr>
      <th width="45%">
        To
      </th>

      <th>
        Read
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        Run a first request from a script
      </td>

      <td>
        [Python quickstart](/audio-decisions/docs/quickstart/python)

        , 

        [TypeScript quickstart](/audio-decisions/docs/quickstart/typescript)
      </td>
    </tr>

    <tr>
      <td>
        Find example questions for a task
      </td>

      <td>
        [Use cases](/audio-decisions/docs/use-cases)
      </td>
    </tr>

    <tr>
      <td>
        Choose whose voice and how much audio to send
      </td>

      <td>
        [Preparing your audio](/audio-decisions/docs/preparing-your-audio)
      </td>
    </tr>

    <tr>
      <td>
        Word questions and criteria
      </td>

      <td>
        [Writing questions](/audio-decisions/docs/writing-questions)
      </td>
    </tr>

    <tr>
      <td>
        Act on answers and set thresholds
      </td>

      <td>
        [Interpreting answers](/audio-decisions/docs/interpreting-answers)
      </td>
    </tr>

    <tr>
      <td>
        Read every field of each question type
      </td>

      <td>
        [Primitives](/audio-decisions/docs/primitives)
      </td>
    </tr>

    <tr>
      <td>
        Check the exact request and response schema
      </td>

      <td>
        [Create decision](/audio-decisions/reference/decisions/create)
      </td>
    </tr>

    <tr>
      <td>
        Estimate the input tokens of a request before sending it
      </td>

      <td>
        [Estimate input tokens](/audio-decisions/reference/decisions/input-tokens)
      </td>
    </tr>

    <tr>
      <td>
        Look up past requests
      </td>

      <td>
        [Runs](/audio-decisions/docs/runs)
      </td>
    </tr>

    <tr>
      <td>
        Check limits and handle errors
      </td>

      <td>
        [Limits](/audio-decisions/docs/limits)

        , 

        [Errors](/audio-decisions/docs/errors)
      </td>
    </tr>

    <tr>
      <td>
        Evaluate many recordings
      </td>

      <td>
        [Evaluating many files](/audio-decisions/docs/evaluating-many-files)

        , 

        [Evaluating many recordings](/audio-decisions/cookbooks/evaluating-many-recordings)
      </td>
    </tr>

    <tr>
      <td>
        Answer live audio
      </td>

      <td>
        [Live audio](/audio-decisions/docs/preparing-your-audio#live-audio)

        , 

        [Answering live audio](/audio-decisions/cookbooks/answering-live-audio)
      </td>
    </tr>
  </tbody>
</table>