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

# Quick start

> Send an audio file to Multilingual Transcription and read the response, in about five minutes.

This page goes from nothing to a transcript. The same shape applies to every other Modulate model: one key, one request, one response.

## Before starting

<Steps>
  <Step title="Get an API key">
    [Create a free account](https://platform.modulate.ai/signup-request), then create a key from the **API Keys** tab in the dashboard.
  </Step>

  <Step title="Store the key">
    Set it as an environment variable rather than hard-coding it.

    ```bash theme={null}
    export MODULATE_API_KEY=your_api_key_here
    ```
  </Step>

  <Step title="Get a sample audio file">
    Download the sample clip into the working directory. The examples below read `audio.mp3` from there.

    ```bash theme={null}
    curl -sSO https://docs.modulate.ai/samples/audio.mp3
    ```

    The [sample](/samples/audio.mp3) is 17 seconds of one speaker. Any speech clip of 5 to 30 seconds works in its place.
  </Step>
</Steps>

The `curl` example pipes the response through [jq](https://jqlang.github.io/jq/) to render it. The Python example needs `requests`:

```bash theme={null}
brew install jq          # or: apt install jq
pip install requests
```

## Make the first call

<CodeGroup>
  ```bash curl + jq theme={null}
  curl -sS -X POST https://platform.modulate.ai/api/velma-2-stt-batch \
    -H "X-API-Key: $MODULATE_API_KEY" \
    -F "upload_file=@audio.mp3" \
  | jq -r 'if .detail then "error: \(.detail)" else
      .text, (.utterances[] | "  [\(.start_ms)ms] Speaker \(.speaker): \(.text)")
    end'
  ```

  ```python Python theme={null}
  import os, requests

  response = requests.post(
      "https://platform.modulate.ai/api/velma-2-stt-batch",
      headers={"X-API-Key": os.environ["MODULATE_API_KEY"]},
      files={"upload_file": open("audio.mp3", "rb")},
  )
  response.raise_for_status()
  result = response.json()

  print(result["text"])
  for u in result["utterances"]:
      print(f"  [{u['start_ms']}ms] Speaker {u['speaker']}: {u['text']}")
  ```

  ```javascript JavaScript theme={null}
  import fs from "fs";
  import FormData from "form-data";

  const form = new FormData();
  form.append("upload_file", fs.createReadStream("audio.mp3"), { filename: "audio.mp3" });

  const response = await fetch("https://platform.modulate.ai/api/velma-2-stt-batch", {
    method: "POST",
    headers: { "X-API-Key": process.env.MODULATE_API_KEY, ...form.getHeaders() },
    body: form,
  });

  const result = await response.json();

  if (!response.ok) {
    console.error(`error: ${result.detail}`);
    process.exit(1);
  }

  console.log(result.text);
  for (const u of result.utterances) {
    console.log(`  [${u.start_ms}ms] Speaker ${u.speaker}: ${u.text}`);
  }
  ```
</CodeGroup>

```text Output theme={null}
Thanks for holding. I've pulled up your account, and it looks like the charge you're asking about posted on Tuesday afternoon. I can open a dispute for you right now, or if you'd rather, I can walk you through what the merchant listed on the statement first. Either way, nothing is final until you confirm it.
  [350ms] Speaker 1: Thanks for holding.
  [1510ms] Speaker 1: I've pulled up your account, and it looks like the charge you're asking about posted on Tuesday afternoon.
  [7030ms] Speaker 1: I can open a dispute for you right now, or if you'd rather, I can walk you through what the merchant listed on the statement first.
  [14590ms] Speaker 1: Either way, nothing is final until you confirm it.
```

A rejected call prints the server's message in place of the transcript:

```text Output theme={null}
error: Invalid API key
```

Every error response carries a `detail` field, which is what the `if` at the front of the jq filter reads. The same guard is on the `curl` example for every endpoint.

The response is `application/json`.

<Accordion title="Response">
  ```json theme={null}
  {
    "text": "Thanks for holding. I've pulled up your account, and it looks like the charge you're asking about posted on Tuesday afternoon. I can open a dispute for you right now, or if you'd rather, I can walk you through what the merchant listed on the statement first. Either way, nothing is final until you confirm it.",
    "duration_ms": 17496,
    "utterances": [
      {
        "utterance_uuid": "5bed95f4-bd8f-495c-a6b8-5acd2f8aa549",
        "text": "Thanks for holding.",
        "start_ms": 350,
        "duration_ms": 1040,
        "speaker": 1,
        "language": "en",
        "emotion": null,
        "accent": null,
        "deepfake_score": null
      },
      {
        "utterance_uuid": "3d534a5f-30a6-48e2-b3f5-bf1b5e735e7b",
        "text": "I've pulled up your account, and it looks like the charge you're asking about posted on Tuesday afternoon.",
        "start_ms": 1510,
        "duration_ms": 5520,
        "speaker": 1,
        "language": "en",
        "emotion": null,
        "accent": null,
        "deepfake_score": null
      },
      {
        "utterance_uuid": "829017e8-54f6-48d0-8150-89a90e2fb5c0",
        "text": "I can open a dispute for you right now, or if you'd rather, I can walk you through what the merchant listed on the statement first.",
        "start_ms": 7030,
        "duration_ms": 7080,
        "speaker": 1,
        "language": "en",
        "emotion": null,
        "accent": null,
        "deepfake_score": null
      },
      {
        "utterance_uuid": "70507be1-ebf2-4346-a0bb-c867da72e756",
        "text": "Either way, nothing is final until you confirm it.",
        "start_ms": 14590,
        "duration_ms": 2560,
        "speaker": 1,
        "language": "en",
        "emotion": null,
        "accent": null,
        "deepfake_score": null
      }
    ]
  }
  ```
</Accordion>

`text` is the full transcript. `utterances` breaks it into speaker turns with millisecond timing and a language detected per utterance. `emotion`, `accent`, and `deepfake_score` are `null` until those signals are enabled. See [Transcription](/get-started/stt).

Response formats differ across the API. Most endpoints return JSON, [PII/PHI Redaction](/get-started/pii) batch returns `multipart/form-data`, and the streaming endpoints return sequences of JSON messages, some interleaved with binary audio frames. Each capability page states the format for its endpoints.

## Go deeper by capability

Each page states what the endpoint returns, what can be configured, the accepted audio formats, and a runnable call for every endpoint in that family.

<CardGroup cols={3}>
  <Card title="Velma Triage" icon="comments" href="/get-started/velma">
    Behaviors, topics, sentiment, and a summary across a whole conversation.
  </Card>

  <Card title="Transcription" icon="microphone" href="/get-started/stt">
    Multilingual, English Fast, and Multilingual Fast. Batch and streaming.
  </Card>

  <Card title="Deepfake Detection" icon="shield-halved" href="/get-started/deepfake">
    Per-frame synthetic-voice verdicts on files or live audio.
  </Card>

  <Card title="PII/PHI Redaction" icon="eye-slash" href="/get-started/pii">
    A redacted transcript plus audio with the sensitive ranges silenced.
  </Card>

  <Card title="Emotion Detection" icon="face-smile" href="/get-started/emotion">
    A whole-file emotion label plus a per-window time series.
  </Card>

  <Card title="Accent Detection" icon="globe" href="/get-started/accent">
    A whole-file accent label plus a per-window time series.
  </Card>

  <Card title="Music & Speech Detection" icon="music" href="/get-started/music-detection">
    Frame-level music and speech probabilities.
  </Card>

  <Card title="AI Music Detection" icon="robot" href="/get-started/ai-music-detection">
    Whether a track contains AI-generated vocals or instrumentals.
  </Card>

  <Card title="Audio Event Detection" icon="waveform-lines" href="/get-started/audio-event-detection">
    Which non-speech sound events are present, from a vocabulary of 42 spanning instruments to gunshots.
  </Card>

  <Card title="Language Detection" icon="language" href="/get-started/language-detection">
    The spoken language of a clip, with a confidence score.
  </Card>
</CardGroup>

[Which API should I use?](/guides/which-api) works from the output backwards to the endpoint that produces it.

## Combine models

One endpoint answers one question. Most production decisions read two or more outputs together.

<Card title="Screen a call for voice fraud" icon="user-shield" href="/get-started/voice-fraud-screening">
  Run Deepfake Detection and Velma Triage on one recording, aggregate the frame verdicts, and combine both outputs into a single screening decision.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.