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

# Downloading YouTube Video Subtitles

> Look up the subtitle tracks available on a YouTube video, then download one as a file

## Overview

Downloading YouTube subtitles is a two-call workflow, where the second call returns a file.

## Before you start

* Get an API key. For details, see [Authentication](/api-v3/authentication.md).
* Check your credit balance by calling `GET /usage`. Purchase additional API credits through the **API dashboard** in the CreatorDB App if needed.
* Get the YouTube video ID. For details, see [How to Get A YouTube Video ID](/creatordb_app/tutorials/how_to_get_a_youtube_video_id.md).

**1. List the available subtitle tracks**

Calling `GET /youtube/subtitles/meta` returns every subtitle language on the video, each
with a `vssId`. Costs 1 credit.

**2. Download a subtitle track**

Calling `GET /youtube/subtitles/download` takes a `vssId` from Step 1 and streams that
track back as a file. Costs 3 credits.

Because you cannot know in advance which tracks a video has, list them first.

> [!WARNING]
>
> The download endpoint **streams a file attachment and does not return the standard JSON envelope**. It is the only API endpoint that behaves this way. For details, see [The download response is not a standard JSON envelope](#the-download-response-is-not-a-standard-json-envelope).

## Step 1: List available subtitle tracks

**Request**

```bash theme={null}
curl -G "https://apiv3.creatordb.app/youtube/subtitles/meta" \
  --header 'api-key: YOUR_API_KEY' \
  --data-urlencode 'videoId=icxrUIGoEg8'
```

> [!NOTE]
>
> The `videoId` is the 11-character YouTube video ID. It may include letters (a-z, A-Z), numbers (0-9), hyphens (-), and underscores (\_).

**Response**

```json theme={null}
{
  "data": {
    "videoId": "icxrUIGoEg8",
    "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "availableSubtitles": [
      {
        "vssId": "a.en",
        "lang": "English (Auto-generated)",
        "langCode": "en"
      },
      {
        "vssId": ".zh-Hant",
        "lang": "Chinese (Traditional)",
        "langCode": "zh"
      }
    ]
  },
  "creditsUsed": 1,
  "creditsAvailable": 99759,
  "traceId": "f8e4a3b2c1d0e9f8a7b6c5d4e3f2a1b0",
  "timestamp": 1750732453635,
  "errorCode": "",
  "errorDescription": "",
  "success": true
}
```

| Field | Description |
| - | - |
| `vssId` | The subtitle track code. This is the value you pass to the download endpoint. |
| `lang` | The full language name as YouTube reports it, including the auto-generated marker. |
| `langCode` | The language in ISO 639-1 two-letter form. For details, see [Codes for the Representation of Names of Languages](https://www.loc.gov/standards/iso639-2/php/English_list.php). |

A video can have more than one track for the same language. For example, separate auto-generated and manual English tracks, both returned with `"langCode": "en"`. Because `langCode` can repeat like that, select a track by its `vssId`, which is unique, rather than by `langCode`.

### What the prefix means

The prefix in `vssId` indicates how the subtitle track was created:

* **Auto-generated** (an `a` before the period, e.g. `a.en`): Machine-generated tracks. Widely available, but may contain transcription errors.
* **Human-authored** (no `a` before the period, e.g. `.en`): Tracks supplied by the video creator or a contributor. Less common, but usually more accurate where they exist.

## Step 2: Download a subtitle track

**Request**

```bash theme={null}
curl -G "https://apiv3.creatordb.app/youtube/subtitles/download" \
  --header 'api-key: YOUR_API_KEY' \
  -o "icxrUIGoEg8-.en.json" \
  --data-urlencode 'videoId=icxrUIGoEg8' \
  --data-urlencode 'vssId=.en'
```

Both `videoId` and `vssId` are required. The `vssId` must match one of the available tracks returned for that specific video in Step 1. Otherwise, the request returns `404 SUBTITLE_VSSID_NOT_FOUND`.

Each subtitle download costs **3 credits** per track. For example, downloading English, Japanese, and Chinese subtitles for one video costs 9 credits in total.

## The download response is not a standard JSON envelope

Every other CreatorDB endpoint returns a standard response envelope containing `data`, `creditsUsed`, `creditsAvailable`,
`traceId`, `timestamp`, `errorCode`, `errorDescription`, and `success`. In contrast, `GET /youtube/subtitles/download` streams the subtitle file directly.

| Aspect | Value |
| - | - |
| `Content-Type` | `application/json` |
| `Content-Disposition` | `attachment; filename="{videoId}-{vssId}.json"` |
| `Transfer-Encoding` | `chunked` |
| `Body` | The raw subtitle data as JSON |

Three consequences for your client:

* **No `creditsUsed` field:** Check credit consumption by calling `GET /usage` rather than looking for a response body field.
* **Save directly to a file:** Write the body directly to a file instead of parsing it as an API response envelope. In `curl`, use `-o` as shown above.
* **Mid-stream failures leave partial data:** Because the response is streamed,
  an error after streaming begins cannot be reported in the body. Always validate the downloaded file for completeness before processing.

Errors caught **before** streaming starts return as standard JSON. This covers request validation (`400 VALIDATION_ERROR`), rate limiting (`429 RATE_LIMIT_EXCEEDED`), and insufficient credits (`402 INSUFFICIENT_CREDITS`).

## Errors

| Status | `errorCode` | Cause |
| - | - | - |
| 400 | `VALIDATION_ERROR` | The `videoId` format or length is invalid, or `vssId` is missing. |
| 402 | `INSUFFICIENT_CREDITS` | Your account ran out of API credits. Purchase additional credits and retry. |
| 404 | `SUBTITLE_VIDEO_NOT_FOUND` | The `videoId` is well-formed but the video is not in the database. |
| 404 | `SUBTITLE_VSSID_NOT_FOUND` | The video exists but does not have that subtitle track. |
| 429 | `RATE_LIMIT_EXCEEDED` | Rate limit reached. Back off and retry. |

A `videoId` with invalid characters and the wrong length triggers both the length and character validation checks. The `details` array of the `400 VALIDATION_ERROR` response then contains two entries for `videoId`. For the complete error response structure, see [Error Codes](/api-v3/error-code.md).

## Related pages

For credit costs across every endpoint, see [API Credit Usage](/api-v3/api-credit-usage.md).


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