API Reference
Base URL: https://api.subdownload.com · Auth: Authorization: Bearer sk_live_xxx
Endpoints
GET
/v1/verify
free
Verify an API key is valid. Returns token and user info. Does not consume credits.
Request
curl -H "Authorization: Bearer sk_live_xxx" https://api.subdownload.com/v1/verify
Response 200
{
"valid": true,
"token": { "name": "My App", "prefix": "sk_live_abc", "monthly_quota": 0, "used_quota": 120 },
"user": { "id": 42, "email": "user@example.com", "plan": "free", "credits_remaining": 148 }
}
GET
/v1/youtube/transcript
1 credit
Fetch the transcript / captions for a YouTube video. Accepts a video ID or any valid YouTube URL (watch, youtu.be, shorts).
Parameters
| Name | Type | Required | Description |
video_id | string | REQUIRED | 11-char video ID or full YouTube URL. Alias: video_url. |
lang | string | optional | Preferred language codes, comma-separated (e.g. en,zh,ja). |
Request
curl -H "Authorization: Bearer sk_live_xxx" "https://api.subdownload.com/v1/youtube/transcript?video_id=dQw4w9WgXcQ&lang=en"
Response 200
{
"data": {
"video_id": "dQw4w9WgXcQ",
"language": "en",
"segments": [
{ "text": "We're no strangers to love", "start": 0.0, "duration": 3.5 }
],
"text": "We're no strangers to love...",
"meta": { "title": "...", "author": "...", "thumbnail": "..." }
},
"credits_used": 1,
"credits_remaining": 148
}
Errors
400 missing video_id · 404 no captions · 402 credits exhausted
GET
/v1/youtube/search
1 credit
Search YouTube for videos or channels matching a keyword query.
Parameters
| Name | Type | Required | Description |
q | string | REQUIRED | Search query (1-200 chars). |
type | string | optional | video (default) or channel. |
limit | integer | optional | 1-50 results (default 20). |
Request
curl -H "Authorization: Bearer sk_live_xxx" "https://api.subdownload.com/v1/youtube/search?q=rust+tutorial&limit=5"
GET
/v1/youtube/channel/resolve
free
Resolve any channel reference (@handle, URL, or UC… ID) to canonical channel info.
Parameters
| Name | Type | Required | Description |
input | string | REQUIRED | @handle, channel URL, video URL, or UC… ID. |
GET
/v1/youtube/channel/search
1 credit
Search within a specific channel's videos.
Parameters
| Name | Type | Required | Description |
channel | string | REQUIRED | @handle, URL, or UC… ID (alias: channel_id). |
q | string | REQUIRED | Search query. |
limit | integer | optional | 1-50 (default 30). |
GET
/v1/youtube/channel/latest
free
Fetch the most recent ~15 videos from a channel via RSS. Fast and free.
Parameters
| Name | Type | Required | Description |
channel | string | REQUIRED | @handle, URL, or UC… ID (alias: channel_id). |
GET
/v1/youtube/channel/videos
1 credit/page
List all videos uploaded by a channel, paginated ~100 per page.
Parameters
| Name | Type | Required | Description |
channel | string | first page | @handle, URL, or UC… ID (alias: channel_id). |
continuation | string | next pages | Token returned from the previous call. |
Note: Provide either channel or continuation, not both.
GET
/v1/youtube/playlist/videos
1 credit/page
List videos in a YouTube playlist with pagination.
Parameters
| Name | Type | Required | Description |
playlist | string | first page | Playlist URL or ID (PL…, UU…, LL…, FL…, OL…). |
continuation | string | next pages | Token from previous response. |
AI Transcription (ASR)
Run Whisper on videos that have no captions. Async: POST enqueues a task, then you poll GET until status=done. 5 credits, debited only on successful completion — re-running ASR on a video you already paid for is free.
POST
/v1/youtube/asr
5 credits on done
Start an async AI Whisper transcription. Returns task_id with ETA hints so you can pace polling.
Body (JSON)
| Name | Type | Required | Description |
video_url | string | REQUIRED | YouTube URL (watch, youtu.be, shorts, embed). |
lang | string | optional | Language hint (e.g. en, zh). Omit to auto-detect. |
Request
curl -X POST -H "Authorization: Bearer sk_live_xxx" -H "Content-Type: application/json" -d '{"video_url":"https://youtu.be/dQw4w9WgXcQ"}' https://api.subdownload.com/v1/youtube/asr
Response 202
{
"task_id": "task_01HX...",
"status": "queued",
"from_cache": false,
"queue_position": 2,
"estimated_wait_seconds": 61,
"next_poll_after_seconds": 15,
"poll_url": "/v1/youtube/asr/task_01HX..."
}
Pace polling with next_poll_after_seconds. Cache hits return status=done immediately with segments inlined.
GET
/v1/youtube/asr/{task_id}
free
Poll an ASR task. Free — no credits, no token quota. Owner-scoped: only the creator can read.
Response 200 (done)
{
"task": {
"task_id": "task_01HX...",
"status": "done",
"detected_lang": "en",
"duration_seconds": 213,
"segments": [
{ "start": 0.0, "end": 3.5, "text": "..." }
],
"stage_progress": 1
},
"estimated_wait_seconds": 0,
"next_poll_after_seconds": 0
}
Statuses: queued · downloading · transcribing · done · failed · cancelled. Only when status=done are segments final.
Library
Per-user storage for saved transcripts and AI summaries. Reads are free; writes consume one token-quota unit. No user credits are charged on this API.
GET
/v1/library
free
List items the user has saved to their Library (transcripts and summaries).
Parameters
| Name | Type | Required | Description |
favorite | string | optional | 1 or true to return favorites only. |
q | string | optional | Title / author substring match. |
tag | string | optional | Filter by tag. |
limit | integer | optional | 1–100 (default 20). |
offset | integer | optional | Pagination offset. |
Response 200
{
"items": [
{
"id": 42,
"video_id": "dQw4w9WgXcQ",
"title": "...", "thumbnail": "...",
"has_asr": true,
"has_summary": true,
"is_favorite": false
}
],
"total": 7, "limit": 20, "offset": 0
}
GET
/v1/library/{id}
free
Get a single Library item's metadata. Use has_asr / has_summary flags to decide which content endpoint to call next.
GET
/v1/library/{id}/transcript
free
Fetch the ASR segments and joined text for a Library item. Returns 404 when no completed ASR exists for the video.
Response 200
{
"task_id": "task_01...",
"detected_lang": "en",
"duration_seconds": 213,
"text": "joined
segment
text...",
"segments": [{ "start": 0.0, "end": 3.5, "text": "..." }]
}
GET
/v1/library/{id}/summary
free
Fetch the stored summary text for a Library item. Use ?locale= to pick among stored locales (defaults to Accept-Language then en).
Response 200
{
"locale": "en",
"text": "...",
"model": "claude-opus-4",
"updated_at": "2026-04-22T..."
}
Returns 404 when no summary row exists for that (video_id, locale). Clients can retry with a different ?locale=.
POST
/v1/library
free (1 token-quota unit)
kind=asr flags a saved transcript (segments already live in the ASR table). kind=summary uploads a pre-generated summary text into our summaries table and marks has_summary=true. Upserts on (video_id, locale).
Body (JSON)
| Name | Type | Required | Description |
video_id | string | REQUIRED | YouTube video ID. |
kind | string | REQUIRED | asr or summary. |
title / author / thumbnail / video_url / language / tag | string | optional | Metadata for display and filtering. |
locale | string | summary mode | Locale for the summary (defaults to Accept-Language then en). |
text | string | when kind=summary | Summary text to persist. |
model | string | optional | LLM identifier (e.g. claude-opus-4). |
Request (upload a summary)
curl -X POST -H "Authorization: Bearer sk_live_xxx" -H "Content-Type: application/json" -d '{
"video_id": "dQw4w9WgXcQ",
"kind": "summary",
"locale": "en",
"text": "This video covers...",
"model": "claude-opus-4",
"title": "..."
}' https://api.subdownload.com/v1/library
DELETE
/v1/library/{id}
free
Soft-delete a Library item. A subsequent POST /v1/library for the same video restores the row instead of creating a duplicate.
Official SDKs
Use our official client libraries to integrate the API quickly:
→ Full source: github.com/SubDownload/api-sdk
→ For billing, rate limits, and error codes see Support & Billing.