← back to app

Developer API

Every credit-gated endpoint accepts either the web session cookie or an API key via Authorization: Bearer ytt_…. Billing is identical: the same credits, the same costs.

Quick start

  1. Create a key below (shown once — store it somewhere safe).
  2. curl "https://<host>/api/transcript?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ&format=srt" \
      -H "Authorization: Bearer ytt_YOUR_KEY"

Your API keys

Endpoints

GET/api/transcriptAPI key or session

Fetch a video's transcript. 1 credit per successful fetch.

params: url (watch URL / youtu.be / bare 11-char ID), lang (ISO 639-1, e.g. fi), format = json (default) | txt | srt | vtt | csv | bi-srt (requires lang), source = auto (default) | captions | asr

202 → {status: "asr_started", videoId} when captions are missing and ASR has started (poll the job endpoint).

POST/api/summarizeAPI key or session

Summarize a video with the local LLM. 1 credit per call (transcript + summary together).

body: {'url': string, 'lang'?: string} — watch URL / youtu.be / bare 11-char ID. Fetches the transcript (captions, or AI transcription when the video has none), then generates a concise summary: TL;DR, Key points, Takeaway.

202 → {status: \\"asr_started\\"} when captions are missing and transcription is still running — retry in a couple of minutes.

GET/api/asr/job?videoId=<id>API key or session

Poll an ASR job. Free (the job was charged at start).

params: videoId, optional format, lang. Returns job status until done, then the full result.

POST/api/batchAPI key or session

Batch up to 25 videos. 1 credit per SUCCESSFUL video.

body: {'urls': string[], 'playlist'?: string, 'lang'?: string} — playlist/channel links are expanded server-side.

202 → {batchId, total}; 402 if you don't have credits for the whole batch (nothing starts).

GET/api/batch/status?batchId=<id>API key or session

Lightweight batch progress (no segments).

GET/api/batch/download?batchId=<id>&format=srtAPI key or session

Download batch results — combined file, or add &videoId=<id> for one. Free.

POST/api/mcpAPI key or session

MCP (Model Context Protocol) Streamable-HTTP server — youtube_transcript, youtube_transcript_translate, youtube_transcript_batch tools. 1 credit per video.

GET/api/keyssession cookie only

List your API keys (metadata only — plaintexts are never stored).

POST/api/keyssession cookie only

Create a key: body {"name"}. Plaintext returned once, 201.

DELETE/api/keys?id=<keyId>session cookie only

Revoke a key — immediate.

Export formats

format=csv — spreadsheet-ready, RFC 4180. Columns: index, start_s, end_s, text (times in float seconds).

curl "https://<host>/api/transcript?url=...&format=csv" -H "Authorization: Bearer ***"
# index,start_s,end_s,text
# 1,1.360,3.040,"♪ We're no strangers to love ♪"

format=bi-srt (requires lang=TARGET) — two-line cues: original line under the translated line. Import as bilingual subtitles for language learning. If target equals the source language you get plain SRT. Also available on /api/asr/job and batch downloads (csv only).

curl "https://<host>/api/transcript?url=...&lang=fi&format=bi-srt" -H "Authorization: Bearer ***"
# 1
# 00:00:01,360 --> 00:00:21,880
# ♪ We're no strangers to love ♪
# ♪ Emme ole vieraana rakkautta ♪

MCP server

Plug transcripts into any MCP client — Claude Desktop, Cursor, or agent frameworks. POST /api/mcp speaks the MCP Streamable-HTTP protocol. Auth is your existing API key (Authorization: Bearer ***). Same credits, same costs: 1 credit per video (batch is capped at 5 per call).

Tools: youtube_transcript (json/txt/srt/vtt/csv), youtube_transcript_translate (target_lang), youtube_transcript_batch (max 5), youtube_transcript_summary (TL;DR + key points + takeaway).

curl "https://<host>/api/mcp" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Authorization: Bearer ***" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"youtube_transcript","arguments":{"url":"dQw4w9WgXcQ","format":"txt"}}}'

Claude Desktop config (claude_desktop_config.json):

{
  "mcpServers": {
    "yttranscript": {
      "url": "https://<host>/api/mcp",
      "headers": { "Authorization": "***" }
    }
  }
}

Credits & errors

actioncost
caption fetch / ASR job start1 credit
translation1 credit / 2,500 chars
ASR1 credit / 90 s of audio
batch item (success only)1 credit

401 — missing/invalid auth (no cookie, bad key).

402 — {insufficientCredits: true} out of credits.

400 — bad input (malformed URL etc. — never charged).

404 — video unavailable / no captions / batch expired (24 h).

429 — YouTube rate limit. 502 — upstream failure.

Rate limits & concurrency

There is no per-key request rate limit — you are bounded by your credit balance and by YouTube’s own rate-limiting (a 429 means YouTube, not us, asked you to slow down). The enforced caps that do exist:

LimitValueScope
Batch size25 videos / jobper POST /api/batch
Batch-internal parallelism2 concurrent fetchesper batch job
MCP batch5 videos / callper youtube_transcript_batch
Uploads (local files)5 / hourper user, in-memory (resets on restart)
ASRasynchronous jobstart returns 202 + job ID; poll /api/asr/job

Max concurrent requests: not enforced per key. You can issue requests in parallel up to your credit balance; the practical ceiling is YouTube returning 429s and the ASR queue (long audio transcribes over a few minutes). If you see 429s, back off and retry — do not hammer it, or YouTube will extend the window.

Recommended pattern: for bulk work, use POST /api/batch (25 at a time, 2 in flight) rather than firing 25 single requests at once — it is what the server-side parallelism is built for.

Notes

  • Keys are hashed (SHA-256) at rest; a leaked key can be revoked instantly and nothing else is exposed.
  • Batch results persist 24 h after the job finishes.
  • Upload and auth rate limits are in-memory per process and reset on server restart — they are a spam guard, not a hard SLA.