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

# Transcription

> Transcribe an audio or video file into timestamped text using the Python or TypeScript SDK

## Overview

Convert spoken audio or video into accurate, timestamped text with speaker labels. The pipeline is asynchronous: submit a job with a local file or a public URL, poll until it completes, then retrieve the segmented transcript.

### Prerequisites

<Steps>
  <Step title="Create an account">
    Sign up at [CAMB.AI Studio](https://studio.camb.ai) if you haven't already.
  </Step>

  <Step title="Get your API key">
    Go to **Settings → API Keys** in Studio and copy your key. See [Authentication](/getting-started/authentication) for details.
  </Step>

  <Step title="Install the SDK">
    <CodeGroup>
      ```bash Python theme={null}
      pip install camb-sdk
      ```

      ```bash TypeScript theme={null}
      npm install @camb-ai/sdk
      ```
    </CodeGroup>

    Skip this step if you're using the [direct API](/tutorials/direct-api).
  </Step>

  <Step title="Set your API key to use in your code">
    ```bash theme={null}
    export CAMB_API_KEY="your_api_key_here"
    ```
  </Step>
</Steps>

***

## Code

<CodeGroup>
  ```python Python theme={null}
  import os
  import time
  from camb.client import CambAI
  from camb.types.language_enums import Languages

  client = CambAI(api_key=os.getenv("CAMB_API_KEY"))

  def transcribe_audio():
      # Step 1: Submit the transcription job
      response = client.transcription.create_transcription(
          language=Languages.EN_US,  # English (US)
          media_url="https://example.com/meeting.mp3",
          transcription_mode="fast",
      )

      task_id = response.task_id
      print(f"Transcription task created: {task_id}")

      # Step 2: Poll until complete
      while True:
          status = client.transcription.get_transcription_task_status(task_id=task_id)
          print(f"Status: {status.status}")

          if status.status == "SUCCESS":
              # Step 3: Retrieve the transcript
              result = client.transcription.get_transcription_result(run_id=status.run_id)
              for segment in result.transcript[:3]:
                  print(f"[{segment.start:.2f}-{segment.end:.2f}] {segment.speaker}: {segment.text}")
              break
          elif status.status == "ERROR":
              print(f"Transcription failed: {status.exception_reason}")
              break

          time.sleep(5)

  transcribe_audio()
  ```

  ```javascript TypeScript theme={null}
  import { CambClient, CambApi } from '@camb-ai/sdk';

  const client = new CambClient({
      apiKey: process.env.CAMB_API_KEY
  });

  async function transcribeAudio() {
      // Step 1: Submit the transcription job
      const response = await client.transcription.createTranscription({
          language: CambApi.Languages.EN_US, // English (US)
          media_url: 'https://example.com/meeting.mp3',
          transcription_mode: 'fast'
      });

      const taskId = response.task_id;
      console.log(`Transcription task created: ${taskId}`);

      // Step 2: Poll until complete
      while (true) {
          const status = await client.transcription.getTranscriptionTaskStatus({
              task_id: taskId
          });

          console.log(`Status: ${status.status}`);

          if (status.status === 'SUCCESS') {
              // Step 3: Retrieve the transcript
              const result = await client.transcription.getTranscriptionResult({
                  run_id: status.run_id
              });

              for (const segment of result.transcript.slice(0, 3)) {
                  console.log(
                      `[${segment.start.toFixed(2)}-${segment.end.toFixed(2)}] ${segment.speaker}: ${segment.text}`
                  );
              }
              break;
          } else if (status.status === 'ERROR') {
              console.error(`Transcription failed: ${status.exception_reason}`);
              break;
          }

          await new Promise(resolve => setTimeout(resolve, 5000));
      }
  }

  transcribeAudio();
  ```
</CodeGroup>

### Transcribing a local file

Pass `media_file` instead of `media_url` to upload a local file:

<CodeGroup>
  ```python Python theme={null}
  with open("meeting.mp3", "rb") as audio_file:
      response = client.transcription.create_transcription(
          language=Languages.EN_US,
          media_file=audio_file
      )
  ```

  ```javascript TypeScript theme={null}
  import { createReadStream } from 'fs';

  const response = await client.transcription.createTranscription({
      language: CambApi.Languages.EN_US,
      media_file: createReadStream('meeting.mp3')
  });
  ```
</CodeGroup>

***

## Parameters

### Required

| Parameter                     | Type             | Description                                                                                                                                                                                          |
| ----------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `language`                    | `Languages` enum | Source language for the spoken content (e.g. `Languages.EN_US`). The raw API also accepts locale-tag strings like `"en-us"`; numeric IDs still work but are deprecated. See [Languages](#languages). |
| `media_file` *or* `media_url` | file *or* string | Provide exactly one — a local audio/video file, or a publicly accessible URL.                                                                                                                        |

### Optional

| Parameter               | Type             | Description                                                                                                                   |
| ----------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `project_name`          | string           | Label for the job in your dashboard                                                                                           |
| `project_description`   | string           | Additional notes for the job                                                                                                  |
| `folder_id`             | integer          | Place the run inside a specific folder                                                                                        |
| `transcription_mode`    | `fast` or `slow` | Choose a faster transcript or a more thorough pass; defaults to `fast`                                                        |
| `word_level_timestamps` | boolean          | Passed to `get_transcription_result` / `getTranscriptionResult` to return per-word timing in addition to segment-level timing |

### Result shape

`get_transcription_result` returns a `TranscriptionResult` with a `transcript` array. Each segment contains:

| Field     | Type   | Description                      |
| --------- | ------ | -------------------------------- |
| `start`   | float  | Segment start time in seconds    |
| `end`     | float  | Segment end time in seconds      |
| `text`    | string | Transcribed text for the segment |
| `speaker` | string | Speaker label (e.g. `Speaker 1`) |

***

## Languages

The Python and TypeScript SDKs expect the `Languages` enum:

| Language         | Enum              | Locale (raw API) |
| ---------------- | ----------------- | ---------------- |
| English (US)     | `Languages.EN_US` | `en-us`          |
| Spanish (Spain)  | `Languages.ES_ES` | `es-es`          |
| French (France)  | `Languages.FR_FR` | `fr-fr`          |
| German (Germany) | `Languages.DE_DE` | `de-de`          |
| Mandarin Chinese | `Languages.ZH_CN` | `zh-cn`          |
| Japanese (Japan) | `Languages.JA_JP` | `ja-jp`          |
| Arabic           | `Languages.AR_SA` | `ar-sa`          |

If you're calling the API directly (not via the SDK), pass the locale tag. Numeric language IDs still work but are deprecated.

<Card icon="languages" href="/api-reference/endpoint/get-source-languages" arrow={true} cta="Browse all languages">
  For the full list of supported source languages, see the Source Languages reference.
</Card>

***

## Tips

* **Supported formats:** `.mp3`, `.wav`, `.aac`, `.flac`, `.mp4`, `.mov`, and `.mxf` (MXF is enterprise-only). For best quality use a lossless format like WAV or FLAC.
* **File size:** Uploaded files must be under 20 MB. For longer recordings, host the file and pass a `media_url` instead, or split the recording into chunks.
* **Polling timeout:** For long media, cap your polling loop (e.g. 60 attempts x 5s = 5 minutes) and handle the timeout gracefully.
* **Word-level timestamps:** Set `word_level_timestamps=true` when fetching the result to get precise per-word timing — useful for karaoke-style highlighting and subtitle alignment.
* **Pick the right language:** Specifying the correct source language significantly improves accuracy. For multilingual content, choose the predominant language.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Create Transcription API" icon="book" href="/api-reference/endpoint/create-transcription">
    Full API reference for the transcription endpoint.
  </Card>

  <Card title="Poll Transcription Result" icon="clock" href="/api-reference/endpoint/poll-transcription-result">
    Status polling endpoint reference.
  </Card>

  <Card title="Get Transcription Run Result" icon="captions" href="/api-reference/endpoint/get-transcription-run-result">
    Retrieve the transcript segments and timing data.
  </Card>

  <Card title="Dubbing" icon="video" href="/tutorials/dubbing-with-sdk">
    Translate a video into another language while preserving the original voice.
  </Card>
</CardGroup>
