# Bulk YouTube transcript extractor API

Extract available captions from a pasted list of up to 20 YouTube videos.

Canonical: https://fetchfox.net/docs/bulk-youtube-transcripts-api

## Request

POST /youtube/transcript/bulk (JSON only; no GET). Authenticate with x-access-key. Keep keys server-side.

Credits: 1 credit per usable successful video, including cached transcripts. Failed and unattempted items cost zero. If billing confirmation is unknown, check balance and request history before retrying.

### curl

```
curl --fail-with-body 'https://api.fetchfox.net/youtube/transcript/bulk' -X POST \
  -H 'x-access-key: YOUR_KEY' -H 'Content-Type: application/json' \
  --data '{"urls":["https://www.youtube.com/watch?v=VIDEO_ID"]}'
```

### JavaScript

```
const response = await fetch('https://api.fetchfox.net/youtube/transcript/bulk', {
  method: 'POST', headers: {'Content-Type': 'application/json', 'x-access-key': process.env.FETCHFOX_API_KEY},
  body: JSON.stringify({"urls":["https://www.youtube.com/watch?v=VIDEO_ID"]}), signal: AbortSignal.timeout(130000)
});
if (!response.ok) throw new Error('HTTP ' + response.status);
const batch = await response.json();
for (const item of batch.results) console.log(item.url, item.success, item.attempted, item.creditsUsed);
// Inspect failures and Retry-After. Do not automatically resubmit the batch.
```

### Python

```
import json, os
from urllib.request import Request, urlopen
request = Request('https://api.fetchfox.net/youtube/transcript/bulk', data=json.dumps({"urls":["https://www.youtube.com/watch?v=VIDEO_ID"]}).encode(), headers={'Content-Type':'application/json','x-access-key':os.environ['FETCHFOX_API_KEY']}, method='POST')
with urlopen(request, timeout=130) as response:
    batch = json.load(response)
for item in batch['results']:
    print(item['url'], item['success'], item['attempted'], item['creditsUsed'])
# Retain each result. Review failures before any manual retry.
```

## Submit a bounded batch

POST accepts either urls (1–5 video URL strings) with shared country/enableProxy/no_cache options, or requests (1–5 objects containing url and those options). Only video URLs are accepted. The website deduplicates up to 20 pasted URLs and submits batches of up to five sequentially. No channel or playlist discovery is performed.

Items run sequentially under one request deadline: 60 seconds for free traffic and 120 seconds for paid traffic. A deadline, credit shortage, request capacity limit or billing failure stops later items. A content failure can leave other items eligible to run.

## Handle partial results and charges

The response retains ordered results and summary (total, successful, failed, creditsUsed). HTTP 200 and success=true mean the batch envelope completed, not that every video succeeded. Check each result.success before reading data.transcript or data.transcriptSegments. Each result also has attempted, creditsUsed, chargeStatus, and errorCode/retryable on failure.

A successful item has its own billing receipt and costs one credit, including cache hits. Failed or unattempted items have zero confirmed credits. If chargeStatus is unknown, creditsUsed is null: inspect account history before retrying. summary.creditsUsed and the header report confirmed charges only. Never automatically resubmit a whole batch.

Retry-After may accompany a partial HTTP 200 when admission stopped the batch. Preserve successful results and inspect per-item retryAfter. Stop after current batch in the website prevents the next batch; it does not cancel work already submitted. Leaving the page loses in-memory results, so export before navigating. No server job is created.

## Related pages

- https://fetchfox.net/tools/bulk-youtube-transcripts

- https://fetchfox.net/docs

- https://fetchfox.net/pricing

