SubDownload API
  • 🏠 Home
  • 🛠 Skills
  • ⚡ MCP Integration
  • 📚 Guides & Tutorials
  • 📘 API Reference
  • 💳 Support & Billing
  • 🤖 LLMS.txt
External
  • 🔑 Get API Key
  • 📋 OpenAPI Spec
  • ⚡ MCP Server

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

NameTypeRequiredDescription
video_idstringREQUIRED11-char video ID or full YouTube URL. Alias: video_url.
langstringoptionalPreferred 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

NameTypeRequiredDescription
qstringREQUIREDSearch query (1-200 chars).
typestringoptionalvideo (default) or channel.
limitintegeroptional1-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

NameTypeRequiredDescription
inputstringREQUIRED@handle, channel URL, video URL, or UC… ID.
GET /v1/youtube/channel/search 1 credit
Search within a specific channel's videos.

Parameters

NameTypeRequiredDescription
channelstringREQUIRED@handle, URL, or UC… ID (alias: channel_id).
qstringREQUIREDSearch query.
limitintegeroptional1-50 (default 30).
GET /v1/youtube/channel/latest free
Fetch the most recent ~15 videos from a channel via RSS. Fast and free.

Parameters

NameTypeRequiredDescription
channelstringREQUIRED@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

NameTypeRequiredDescription
channelstringfirst page@handle, URL, or UC… ID (alias: channel_id).
continuationstringnext pagesToken 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

NameTypeRequiredDescription
playliststringfirst pagePlaylist URL or ID (PL…, UU…, LL…, FL…, OL…).
continuationstringnext pagesToken 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)

NameTypeRequiredDescription
video_urlstringREQUIREDYouTube URL (watch, youtu.be, shorts, embed).
langstringoptionalLanguage 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

NameTypeRequiredDescription
favoritestringoptional1 or true to return favorites only.
qstringoptionalTitle / author substring match.
tagstringoptionalFilter by tag.
limitintegeroptional1–100 (default 20).
offsetintegeroptionalPagination 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)

NameTypeRequiredDescription
video_idstringREQUIREDYouTube video ID.
kindstringREQUIREDasr or summary.
title / author / thumbnail / video_url / language / tagstringoptionalMetadata for display and filtering.
localestringsummary modeLocale for the summary (defaults to Accept-Language then en).
textstringwhen kind=summarySummary text to persist.
modelstringoptionalLLM 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:

LanguageRepository
Pythonapi-sdk/python
JavaScriptapi-sdk/javascript
Goapi-sdk/go
Javaapi-sdk/java
Kotlinapi-sdk/kotlin
Rustapi-sdk/rust

→ Full source: github.com/SubDownload/api-sdk

→ For billing, rate limits, and error codes see Support & Billing.