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

# File transcription

> Upload a recording or provide an audio URL and receive its complete transcript in one request.

> [!NOTE]
>
> **Beta.** Transcribe a prerecorded audio or video file with a single HTTP request. You receive the complete transcript when processing finishes.

Use [`POST /v1/asr/transcribe`](https://docs.chariot.in/api-reference/endpoint/asr-transcribe) for a recording you already have. For audio you are still capturing, use the [streaming WebSocket](https://docs.chariot.in/guides/speech-to-text/websocket.md).

## Send a recording

Send `multipart/form-data` with exactly one input:

| Field | Use it for |
| - | - |
| `input_audio_file` | Upload the file bytes from your application. |
| `input_audio_url` | Let Chariot fetch a file from a publicly reachable HTTP or HTTPS URL, including a signed URL. |

Use a direct media URL, not a webpage or a storage object identifier. A signed URL must remain valid while Chariot downloads the file. URLs that require additional authentication headers or access to a private network cannot be fetched.

Send an encoded media file such as WAV, MP3, FLAC, OGG, M4A, AAC, or WebM. Video containers such as MP4 must contain an audio track. Chariot reads the audio from the file; you do not need to convert it to the raw audio format used by the WebSocket API.

### Upload a file

Create an API key in the [Dashboard](https://platform.chariot.in). Keep it on your server and supply it through the `CHARIOT_API_KEY` environment variable.

```bash cURL theme={null}
curl --fail-with-body https://api.chariot.in/v1/asr/transcribe \
  -H "chariotai-api-key: $CHARIOT_API_KEY" \
  -F "input_audio_file=@recording.wav"
```

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

with open("recording.wav", "rb") as audio:
    response = requests.post(
        "https://api.chariot.in/v1/asr/transcribe",
        headers={"chariotai-api-key": os.environ["CHARIOT_API_KEY"]},
        files={"input_audio_file": ("recording.wav", audio, "audio/wav")},
    )

response.raise_for_status()
result = response.json()
print(result["text"])
```

```javascript JavaScript (Node.js) theme={null}
import { readFile } from "node:fs/promises";

const form = new FormData();
form.append(
  "input_audio_file",
  new Blob([await readFile("recording.wav")], { type: "audio/wav" }),
  "recording.wav",
);

const response = await fetch("https://api.chariot.in/v1/asr/transcribe", {
  method: "POST",
  headers: { "chariotai-api-key": process.env.CHARIOT_API_KEY },
  body: form,
});

if (!response.ok) {
  throw new Error(`Transcription failed (${response.status}): ${await response.text()}`);
}
const result = await response.json();
console.log(result.text);
```

Let your HTTP client set `Content-Type` and the multipart boundary. The file field contains the file bytes, not a local path string or base64 text. The Python example uses the `requests` package. The JavaScript example runs on a Node.js version with `fetch`, `FormData`, and `Blob` support.

### Use a URL

Supply the URL as a form field on the same endpoint:

```bash theme={null}
curl --fail-with-body https://api.chariot.in/v1/asr/transcribe \
  -H "chariotai-api-key: $CHARIOT_API_KEY" \
  --form-string "input_audio_url=$AUDIO_URL"
```

Set `AUDIO_URL` to the full media URL, including any signature query parameters. Send the URL instead of `input_audio_file`.

## Choose transcription settings

Add these fields to the same multipart form. Omit them to use the defaults.

| Field | Default | What it controls |
| - | - | - |
| `language` | `none` | Requested transcription language, such as `hi` or `en`. Omit it or use `none` for automatic language detection. |
| `model_type` | `chariot-1-asr-realtime` | Public ASR model. Uses the same value as streaming and async transcription. |
| `mode` | `high_accuracy` | File transcription supports only `high_accuracy`. An explicit `balanced` value returns `422`. |
| `style` | `codemix` | Choose `codemix` to keep borrowed words in their own script, or `native` to use the spoken language's script. |
| `include_timestamps` | `false` | Set to `true` to request estimated word timestamps. Applies to uploads and URL inputs. |

```bash theme={null}
curl --fail-with-body https://api.chariot.in/v1/asr/transcribe \
  -H "chariotai-api-key: $CHARIOT_API_KEY" \
  -F "model_type=chariot-1-asr-realtime" \
  -F "language=hi" \
  -F "mode=high_accuracy" \
  -F "style=native" \
  -F "input_audio_file=@recording.wav"
```

See the supported [language codes](https://docs.chariot.in/guides/speech-to-text/modes-and-languages.md#languages) and [writing styles](https://docs.chariot.in/guides/speech-to-text/modes-and-languages.md#styles). The language setting does not request translation. File settings are form fields, rather than WebSocket query parameters.

## Read the result

A successful request returns `200` with JSON. Input audio channels are mixed to mono and returned as one transcript:

```json theme={null}
{
  "model_type": "chariot-1-asr-realtime",
  "request_id": "a38c6b32-1f3a-4f02-a779-478282bce082",
  "created": "2026-10-23T07:00:00Z",
  "text": "Hi, I'd like to move the meeting to Thursday.",
  "duration": 4.82,
  "words": []
}
```

| Field | Meaning |
| - | - |
| `model_type` | Public model used for this transcription. |
| `request_id` | Identifier for this transcription request. Save it with your result for troubleshooting. |
| `created` | Response creation time in UTC. |
| `duration` | Processed audio duration in seconds, not request latency. |
| `text` | Complete recognized text. It can be empty when no speech is recognized. |
| `words` | Estimated word timestamps when requested. An empty array is returned by default. See below for unavailable timing data. |

### Request word timestamps

Add `include_timestamps=true` to the multipart form:

```bash theme={null}
curl --fail-with-body https://api.chariot.in/v1/asr/transcribe \
  -H "chariotai-api-key: $CHARIOT_API_KEY" \
  -F "include_timestamps=true" \
  -F "input_audio_file=@recording.wav"
```

The complete response includes each timed word as `text`, `start`, and `end`:

```json theme={null}
{
  "model_type": "chariot-1-asr-realtime",
  "request_id": "a38c6b32-1f3a-4f02-a779-478282bce082",
  "created": "2026-10-26T07:00:00Z",
  "text": "Hello world",
  "duration": 2.4,
  "words": [
    { "text": "Hello", "start": 0.25, "end": 0.75 },
    { "text": "world", "start": 0.8, "end": 1.3 }
  ]
}
```

Times are estimates in seconds from the start of the file, including leading silence. They are not processing timestamps. The response still arrives once transcription finishes; this option does not stream the response.

When requested, `words: null` means timing data was unavailable or invalid, while `words: []` means the upstream returned no timed words. You still receive the transcript if timing data is unavailable. When the option is omitted or `false`, `words` remains an empty array. Confidence scores and speaker labels are not returned.

## Request lifecycle

Keep the HTTP request open until the response arrives. Configure your client and any proxy timeouts to allow for both upload and transcription.

This is synchronous file transcription, sometimes called batch or offline transcription. It does not return a background job to poll, deliver webhook results, or accept a CSV or multiple files in one request. Use a separate request for each recording and bound how many requests you send concurrently. For durable background work, multiple recordings, polling, and completion webhooks, use [Async transcription (Beta)](https://docs.chariot.in/guides/speech-to-text/async-transcription.md).

> [!WARNING]
>
> A disconnected or timed-out request does not guarantee that processing finished or that you can resume it. Retrying submits a new transcription request and can result in another charge if the earlier request completed.

Usage is based on audio duration. File transcription shares ASR concurrency with streaming. See [Credits & pricing](https://docs.chariot.in/guides/resources/credits.md) and [Rate limits & concurrency](https://docs.chariot.in/guides/resources/rate-limits.md).

## Handle errors

File acceptance constraints can change during beta. Handle validation errors instead of assuming that every recording can be accepted.

| Status | What to do |
| - | - |
| `401` | Check the API key. |
| `402` | Add sufficient credits before resubmitting. |
| `403` | Check that your plan permits ASR. |
| `413` | Reduce the upload size. |
| `422` | Correct the input or settings. Check that you sent exactly one input, that the file contains readable audio, and that a supplied URL is accessible. |
| `429` | Reduce simultaneous requests and retry with backoff. |
| `502`, `503`, `504` | Transcription could not complete or the selected settings are temporarily unavailable. Inspect the error message before deciding whether to retry. |

Application errors use the `statusCode`, `error`, and `message` fields described in [Errors & troubleshooting](https://docs.chariot.in/guides/resources/errors.md). An upload rejected with `413` before processing can instead return a `detail` message. Check the HTTP status before reading the body.


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