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

# Transcription

> A guide to Daily's transcription REST APIs: real-time transcription during calls, post-call processing via the Batch Processor, and lifecycle events via webhooks.

<Badge color="blue">Paid plans only</Badge>

Daily offers two transcription approaches via the REST API:

* **Real-time** — start, update, and stop transcription during an active call using the `/rooms/{room_name}/transcription` endpoints.
* **Post-call** — submit a recording ID or media URL to the [Batch Processor](/reference/rest-api/batch-processor/index) after a call ends to generate a transcript (and optionally a summary).

Both approaches deliver lifecycle notifications via [webhooks](/reference/rest-api/webhooks).

## Real-time transcription

Real-time transcription runs during an active call and streams text to all in-call participants as speech is detected. Transcripts can optionally be saved to storage as WebVTT files.

### Starting transcription

```bash theme={null}
curl --request POST \
     --url https://api.daily.co/v1/rooms/my-room/transcription/start \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{
       "language": "en",
       "model": "nova-2-general",
       "punctuate": true
     }'
```

<ParamField body="language" type="string" default="'en'">
  BCP-47 language tag. Examples: `'en'`, `'es'`, `'fr'`, `'de'`, `'ja'`, `'pt-BR'`. Available languages depend on the Deepgram model in use.
</ParamField>

<ParamField body="model" type="string">
  Deepgram model name. Examples: `'nova-2-general'`, `'nova-2'`, `'enhanced'`, `'base'`. Higher-tier models offer better accuracy at higher cost.
</ParamField>

<ParamField body="profanity_filter" type="boolean">
  When `true`, Deepgram replaces profane words with asterisks.
</ParamField>

<ParamField body="redact" type="Array<string> | boolean">
  Entities to redact. Pass `true` to redact all supported entities, or an array of strings (e.g. `['pci', 'ssn']`).
</ParamField>

<ParamField body="endpointing" type="number | boolean">
  How long Deepgram waits for silence before ending an utterance. Pass a number (milliseconds) or `true`/`false`.
</ParamField>

<ParamField body="punctuate" type="boolean">
  When `true`, Deepgram adds punctuation to the transcript.
</ParamField>

<ParamField body="instanceId" type="string">
  Identifier for this transcription instance. Required when running multiple simultaneous transcriptions in the same room.
</ParamField>

<ParamField body="participants" type="string[]">
  Array of session IDs. When provided, only those participants' audio is transcribed. Omit to transcribe everyone.
</ParamField>

<Tip>
  Check out [Deepgram's language support documentation](https://developers.deepgram.com/docs/models-languages-overview) for the `model`/`language` combination that works best for your use case.
</Tip>

See the [start transcription endpoint](/reference/rest-api/rooms/transcription/start) for the full API reference.

### Updating transcription

Change which participants are transcribed mid-call:

```bash theme={null}
# Transcribe specific participants only
curl --request POST \
     --url https://api.daily.co/v1/rooms/my-room/transcription/update \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{ "participants": ["af5d66d0-d3fd-4cb8-a2ba-c681e429c8ba"] }'
```

```bash theme={null}
# Restore transcription for everyone (empty array = all)
curl --request POST \
     --url https://api.daily.co/v1/rooms/my-room/transcription/update \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{ "participants": [] }'
```

Include `instanceId` to target a specific instance when running multiple transcriptions simultaneously.

See the [update transcription endpoint](/reference/rest-api/rooms/transcription/update) for the full API reference.

### Stopping transcription

```bash theme={null}
curl --request POST \
     --url https://api.daily.co/v1/rooms/my-room/transcription/stop \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json'
```

To stop a named instance: `--data '{ "instanceId": "primary" }'`

If transcript storage is enabled, the final WebVTT file is written when transcription stops. Listen for the [`transcript.ready-to-download`](#transcript-ready-to-download) webhook to know when the file is available.

See the [stop transcription endpoint](/reference/rest-api/rooms/transcription/stop) for the full API reference.

### Auto-starting transcription

Instead of starting transcription manually, you can have it begin automatically when a meeting owner joins by setting `auto_start_transcription` on their meeting token. Pair it with `auto_transcription_settings` on the room to configure the model and language.

**Meeting token** (triggers auto-start for that owner):

```bash theme={null}
curl --request POST \
     --url https://api.daily.co/v1/meeting-tokens \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{
       "properties": {
         "room_name": "my-room",
         "is_owner": true,
         "auto_start_transcription": true
       }
     }'
```

**Room config** (sets the transcription options used when auto-start fires):

```bash theme={null}
curl --request POST \
     --url https://api.daily.co/v1/rooms/my-room \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{
       "properties": {
         "auto_transcription_settings": {
           "model": "nova-2-general",
           "language": "en"
         }
       }
     }'
```

See the [`auto_start_transcription` meeting token property](/reference/rest-api/meeting-tokens/create-meeting-token#body-properties-auto-start-transcription) and [`auto_transcription_settings` room property](/reference/rest-api/rooms/update-room#body-properties-auto-transcription-settings) for full details.

### Transcript storage

By default, real-time transcripts are streamed to call participants but not saved. To persist transcripts as WebVTT files, enable storage at the room or domain level.

**Room level:**

```bash theme={null}
curl --request POST \
     --url https://api.daily.co/v1/rooms/my-room \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{"properties": {"enable_transcription_storage": true}}'
```

**Domain level:**

```bash theme={null}
curl --request POST \
     --url https://api.daily.co/v1/ \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{"properties": {"enable_transcription_storage": true}}'
```

While transcription is active, the file is written every two minutes. The final version is written when transcription ends.

Transcripts are stored in Daily's cloud by default. To use your own S3 bucket, configure the `transcription_bucket` domain property:

```bash theme={null}
curl --request POST \
     --url https://api.daily.co/v1/ \
     --header 'Authorization: Bearer DAILY_API_KEY' \
     --header 'Content-Type: application/json' \
     --data '{
       "properties": {
         "transcription_bucket": {
           "bucket_name": "my-bucket",
           "bucket_region": "us-east-1",
           "assume_role_arn": "arn:aws:iam::123456789000:role/DAILY_ROLE",
           "allow_api_access": true
         }
       }
     }'
```

The setup process is the same as [configuring a custom S3 bucket for recordings](/docs/guides/features/recording/custom-s3-storage).

## Post-call transcription

The [Batch Processor](/reference/rest-api/batch-processor/index) generates transcripts and summaries from recordings or any publicly accessible audio/video URL — no active call required.

### Submitting a job

Specify a `preset` (`transcript` or `summarize`), an input source, and an output path:

<Tabs>
  <Tab title="From a recording ID">
    ```bash theme={null}
    curl --request POST \
         --url https://api.daily.co/v1/batch-processor \
         --header 'Authorization: Bearer DAILY_API_KEY' \
         --header 'Content-Type: application/json' \
         --data '{
           "preset": "transcript",
           "inParams": {
             "sourceType": "recordingId",
             "recordingId": "uuiasdfe-8ba2-4ee6-bd15-003a92c18245"
           },
           "outParams": {
             "s3Config": { "s3KeyTemplate": "transcript" }
           }
         }'
    ```
  </Tab>

  <Tab title="From a media URL">
    ```bash theme={null}
    curl --request POST \
         --url https://api.daily.co/v1/batch-processor \
         --header 'Authorization: Bearer DAILY_API_KEY' \
         --header 'Content-Type: application/json' \
         --data '{
           "preset": "transcript",
           "inParams": {
             "sourceType": "uri",
             "uri": "https://example.com/recording.mp4"
           },
           "outParams": {
             "s3Config": { "s3KeyTemplate": "transcript" }
           }
         }'
    ```
  </Tab>

  <Tab title="With summary">
    ```bash theme={null}
    curl --request POST \
         --url https://api.daily.co/v1/batch-processor \
         --header 'Authorization: Bearer DAILY_API_KEY' \
         --header 'Content-Type: application/json' \
         --data '{
           "preset": "summarize",
           "inParams": {
             "sourceType": "recordingId",
             "recordingId": "uuiasdfe-8ba2-4ee6-bd15-003a92c18245"
           },
           "outParams": {
             "s3Config": { "s3KeyTemplate": "summary" }
           }
         }'
    ```
  </Tab>
</Tabs>

The response returns a job ID:

```json theme={null}
{ "id": "02c2508e-8835-4f3e-bcf2-e319d00f0eec" }
```

Output formats for `transcript` jobs: `txt`, `srt`, `vtt`, `json`. The `summarize` preset produces a plain text file.

### Retrieving batch job results

Poll job status or get a signed download URL using the job ID returned from submit:

| Endpoint                                                                                 | Description                                                            |
| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [Get job](/reference/rest-api/batch-processor/reference/get-job)                         | `GET /batch-processor/{jobId}` — check status and see output locations |
| [Get job access link](/reference/rest-api/batch-processor/reference/get-job-access-link) | `GET /batch-processor/{jobId}/access-link` — get a signed download URL |
| [List jobs](/reference/rest-api/batch-processor/reference/list-jobs)                     | `GET /batch-processor` — list all jobs for your domain                 |
| [Delete job](/reference/rest-api/batch-processor/reference/delete-job)                   | `DELETE /batch-processor/{jobId}` — delete a job and its output        |

## Events via webhooks

Subscribe to transcription lifecycle events from the [Daily dashboard](https://dashboard.daily.co) or via the [webhooks REST API](/reference/rest-api/webhooks). Events are delivered as POST requests to your webhook URL.

### Real-time transcription events

#### `transcript.started`

Fired when real-time transcription begins. Includes the `instanceId` and, if storage is enabled, the S3 path where the transcript will be written.

```json theme={null}
{
  "version": "1.1.0",
  "type": "transcript.started",
  "payload": {
    "id": "68f65d4c-a4dc-4179-bbb1-c12432afb924",
    "info": { "instanceId": "a1f2f6b7-b1ac-4202-85e5-d446cb6c3d3f" },
    "room_name": "my-transcript-room",
    "mtg_session_id": "a2bc876d-2816-4732-9c87-01e0b8c0b01b",
    "status": "t_in_progress",
    "out_params": {
      "s3": { "key": "domain/room/1733234355482.vtt", "bucket": "daily-co-transcription-staging", "region": "us-west-2" }
    }
  },
  "event_ts": 1733234355.505
}
```

See the [`transcript.started` reference](/reference/rest-api/webhooks/events/transcript-started).

#### `transcript.ready-to-download`

Fired when transcription ends and the saved transcript file is available. This is the completion signal — use `out_params.s3` to locate the file, or use the [get transcript link](/reference/rest-api/transcripts/get-transcript-link) endpoint to get a signed URL.

<Note>
  Despite the name, `transcript.ready-to-download` is the equivalent of "transcription stopped" — it fires when the transcript reaches a finished state. You may also receive a `transcript.error` event if a storage error occurred alongside completion.
</Note>

```json theme={null}
{
  "version": "1.1.0",
  "type": "transcript.ready-to-download",
  "payload": {
    "id": "68f65d4c-a4dc-4179-bbb1-c12432afb924",
    "out_params": {
      "s3": { "key": "domain/room/1733234355482.vtt", "bucket": "daily-co-transcription-staging", "region": "us-west-2" }
    },
    "room_name": "my-transcript-room",
    "duration": 124.405,
    "status": "t_finished"
  },
  "event_ts": 1733234480.097
}
```

See the [`transcript.ready-to-download` reference](/reference/rest-api/webhooks/events/transcript-ready-to-download).

#### `transcript.error`

Fired if an error occurs during transcription or before it could start. Includes an `error` field with details. May fire alongside `transcript.started` or `transcript.ready-to-download` depending on when the error occurred.

```json theme={null}
{
  "version": "1.1.0",
  "type": "transcript.error",
  "payload": {
    "id": "8d5c03f3-cff3-43c7-b112-0f78989f659f",
    "room_name": "my-room",
    "status": "t_error",
    "error": "User is not authorized to perform: s3:PutObject on resource..."
  },
  "event_ts": 1733234946.616
}
```

See the [`transcript.error` reference](/reference/rest-api/webhooks/events/transcript-error).

### Batch Processor events

#### `batch-processor.job-finished`

Fired when a Batch Processor job completes. The `output` field contains S3 locations for all generated files (transcript in all formats, and summary if requested).

```json theme={null}
{
  "version": "1.0.0",
  "type": "batch-processor.job-finished",
  "payload": {
    "id": "1dae15c5-6a85-4d65-ab00-4b19bb054b84",
    "preset": "summarize",
    "status": "finished",
    "output": {
      "transcription": [
        { "format": "json", "s3Config": { "key": "staging/1dae15c5.../transcript/soap.json", "bucket": "...", "region": "us-west-2" } },
        { "format": "txt",  "s3Config": { "key": "staging/1dae15c5.../transcript/soap.txt",  "bucket": "...", "region": "us-west-2" } },
        { "format": "vtt",  "s3Config": { "key": "staging/1dae15c5.../transcript/soap.vtt",  "bucket": "...", "region": "us-west-2" } }
      ],
      "summary": { "format": "txt", "s3Config": { "key": "staging/1dae15c5.../transcript/soap", "bucket": "...", "region": "us-west-2" } }
    }
  },
  "event_ts": 1711402301.747
}
```

See the [`batch-processor.job-finished` reference](/reference/rest-api/webhooks/events/batch-processor-job-finished).

#### `batch-processor.error`

Fired when a Batch Processor job fails. Includes an `error` field with details.

```json theme={null}
{
  "version": "1.0.0",
  "type": "batch-processor.error",
  "payload": {
    "id": "bcb9f15d-2b00-4d98-be5f-23888e2df2ca",
    "preset": "summarize",
    "status": "error",
    "error": "transcript job failed: Error: Failed to download: 403 Forbidden"
  },
  "event_ts": 1711402402.539
}
```

See the [`batch-processor.error` reference](/reference/rest-api/webhooks/events/batch-processor-error).

## Accessing saved transcripts

Both real-time transcripts (when `enable_transcription_storage` is on) and Batch Processor transcripts are accessible via the `/transcript` endpoints. Use these to list, download, and clean up transcripts after the fact.

### Listing transcripts

```bash theme={null}
curl --request GET \
     --url https://api.daily.co/v1/transcript \
     --header 'Authorization: Bearer DAILY_API_KEY'
```

Returns an array of transcript objects for your domain. Each object includes a `transcriptId`, room and session identifiers, `duration`, and `status`.

### Getting a download link

```bash theme={null}
curl --request GET \
     --url https://api.daily.co/v1/transcript/<TRANSCRIPT_ID>/access-link \
     --header 'Authorization: Bearer DAILY_API_KEY'
```

Returns a signed URL to download the WebVTT file. For Batch Processor transcripts, use the [get job access link](/reference/rest-api/batch-processor/reference/get-job-access-link) endpoint instead.

### Deleting a transcript

```bash theme={null}
curl --request DELETE \
     --url https://api.daily.co/v1/transcript/<TRANSCRIPT_ID> \
     --header 'Authorization: Bearer DAILY_API_KEY'
```

| Endpoint                                                                   | Description                                  |
| -------------------------------------------------------------------------- | -------------------------------------------- |
| [List transcripts](/reference/rest-api/transcripts/list-transcripts)       | `GET /transcript`                            |
| [Get transcript](/reference/rest-api/transcripts/get-transcript)           | `GET /transcript/{transcriptId}`             |
| [Get transcript link](/reference/rest-api/transcripts/get-transcript-link) | `GET /transcript/{transcriptId}/access-link` |
| [Delete transcript](/reference/rest-api/transcripts/delete-transcript)     | `DELETE /transcript/{transcriptId}`          |

### The transcript object

A transcript object represents a single transcription session:

```json theme={null}
{
  "transcriptId": "a759ae14-0327-4bf6-ac0d-192a0323f45b",
  "domainId": "04b89420-cf8b-4ea5-a428-02cc0a0e2a59",
  "roomId": "ad9e57d6-dcb8-4bb0-8100-247146b75713",
  "mtgSessionId": "586f7f8b-2a4f-4091-aa85-99a36094cb4e",
  "duration": 14,
  "status": "t_finished",
  "outParams": {
    "key": "my-domain/my-room/1699441864907.vtt",
    "region": "us-west-2",
    "bucket": "test-daily-meeting-recordings"
  }
}
```

Key status values:

* `"t_finished"` — transcription is complete and the file is available
* `"isVttAvailable": true` — the WebVTT file can be downloaded

## Related

<CardGroup cols={2}>
  <Card title="Transcription overview" icon="book" href="/docs/guides/features/transcription">
    Billing, storage options, permissions, and a comparison of real-time vs. post-call approaches.
  </Card>

  <Card title="daily-js guide" icon="js" href="/docs/daily-js/features/transcription">
    Start and manage transcription from a call object with full parameter reference and a live captions example.
  </Card>

  <Card title="Daily React guide" icon="react" href="/docs/daily-react/docs/transcription">
    Use the `useTranscription` hook for reactive transcription state in React apps.
  </Card>
</CardGroup>
