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
- Create a key below (shown once — store it somewhere safe).
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
/api/transcriptAPI key or sessionFetch 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).
/api/summarizeAPI key or sessionSummarize 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.
/api/asr/job?videoId=<id>API key or sessionPoll an ASR job. Free (the job was charged at start).
params: videoId, optional format, lang. Returns job status until done, then the full result.
/api/batchAPI key or sessionBatch 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).
/api/batch/status?batchId=<id>API key or sessionLightweight batch progress (no segments).
/api/batch/download?batchId=<id>&format=srtAPI key or sessionDownload batch results — combined file, or add &videoId=<id> for one. Free.
/api/mcpAPI key or sessionMCP (Model Context Protocol) Streamable-HTTP server — youtube_transcript, youtube_transcript_translate, youtube_transcript_batch tools. 1 credit per video.
/api/keyssession cookie onlyList your API keys (metadata only — plaintexts are never stored).
/api/keyssession cookie onlyCreate a key: body {"name"}. Plaintext returned once, 201.
/api/keys?id=<keyId>session cookie onlyRevoke 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
| action | cost |
|---|---|
| caption fetch / ASR job start | 1 credit |
| translation | 1 credit / 2,500 chars |
| ASR | 1 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:
| Limit | Value | Scope |
|---|---|---|
| Batch size | 25 videos / job | per POST /api/batch |
| Batch-internal parallelism | 2 concurrent fetches | per batch job |
| MCP batch | 5 videos / call | per youtube_transcript_batch |
| Uploads (local files) | 5 / hour | per user, in-memory (resets on restart) |
| ASR | asynchronous job | start 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.