Reach for this when a YouTube playlist is in play: a pasted playlist link or PL.....
Browse playlists and fetch transcripts via TranscriptOut.com.
If $TRANSCRIPTOUT_API_KEY is not set, read references/auth-setup.md and follow the instructions there to get and store the key.
Every request carries these headers:
Bearer $TRANSCRIPTOUT_API_KEYyoutube-skills/youtube-playlist, so TranscriptOut knows the call came from this skillEvery response is one JSON envelope. Success: {"ok": true, "request_id": "...", "data": {...}}. Error: {"ok": false, "code": "...", "detail": "...", "request_id": "..."}. Branch on the machine-readable code, not on the human text. The remaining credit balance rides in the X-Credits-Remaining response header.
Base URL: https://api.transcriptout.com/v1. Full reference with the latest parameters and schemas: transcriptout.com/docs.
Every video of a playlist, in playlist order.
# First page (100 videos)
GET https://api.transcriptout.com/v1/playlist/videos?id=PL_ID_OR_URL
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
X-Client: youtube-skills/youtube-playlist
# Next pages
GET https://api.transcriptout.com/v1/playlist/videos?next_page_token=TOKEN
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
X-Client: youtube-skills/youtube-playlist
# IDs only, 500 per page (feed these into the bulk job)
GET https://api.transcriptout.com/v1/playlist/videos?id=PL_ID_OR_URL&ids_only=true
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
X-Client: youtube-skills/youtube-playlist
id accepts a PL... playlist ID or any URL with list=. limit goes up to 100, or up to 500 with ids_only=true. The response carries playlist, title, count, videos[] (or video_ids[]), next_page_token and has_more.
Find videos inside a playlist by a substring of the title (case-insensitive). YouTube has no native playlist search, so this scans up to 500 playlist items.
GET https://api.transcriptout.com/v1/playlist/search?id=PL_ID_OR_URL&q=QUERY&limit=30
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
X-Client: youtube-skills/youtube-playlist
truncated: true in the response means the scan window ended before the playlist did, so there may be more matches.
For a whole course or series, do not loop single transcript calls: collect the IDs and submit ONE asynchronous job (1 credit per video, up to 4,000).
# 1. Collect the playlist's IDs
GET https://api.transcriptout.com/v1/playlist/videos?id=PL_ID&ids_only=true
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
X-Client: youtube-skills/youtube-playlist
# 2. One bulk job for every video
POST https://api.transcriptout.com/v1/transcripts
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
X-Client: youtube-skills/youtube-playlist
Content-Type: application/json
{"videos":["ID1","ID2","..."],"format":"text"}
# 3. Progress and results
GET https://api.transcriptout.com/v1/transcripts/JOB_ID
Authorization: Bearer $TRANSCRIPTOUT_API_KEY
X-Client: youtube-skills/youtube-playlist
No extraction needed: id accepts the full URL as pasted (youtube.com/playlist?list=PL..., or a watch URL with list=). A bare PL... ID works too.
| Code | Meaning | Action |
|---|---|---|
| 400/422 | Bad parameter | Fix the request. Credit refunded automatically |
| 401 | Bad or missing API key | Check the key. It must start with sk_ |
| 402 | Out of credits | transcriptout.com/billing |
| 404 | No captions on that language/track, or bad ID | Definitive answer, do not retry. Try another lang or kind=auto. Billed |
| 410 | Video removed | Do not retry |
| 451 | Age-restricted or members-only | Do not retry |
| 429 | Rate limit (200 req/min per key) | Wait, respect Retry-After. Refunded |
| 502 | Failed on YouTube's side | One retry is reasonable. Billed |
| 503 | Service at capacity | Retry after Retry-After. Refunded |
Every error body carries a machine-readable code and a request_id. Include the request_id when contacting support.
Every request in this file as a ready-to-run one-liner: references/curl-examples.md