API Endpoints

Complete reference for the SubKit API — 8 endpoints covering subtitle extraction, batch processing, playlist support, AI analysis, and more.

Base URL

Production: https://api.ytsubs.dev

Development: http://localhost:8000

Overview

MethodEndpointDescriptionAuth
POST/extractExtract subtitles from a single videoAPI Key
POST/batchExtract from up to 10 videos in one requestAPI Key
GET/playlistExtract from all videos in a playlistAPI Key
GET/validateCheck subtitle availability before extractingNone
POST/summarizeAI-generated video summaryAPI Key (Pro+)
GET/commentsExtract video commentsAPI Key (Pro+)
POST/comments/analyzeAI sentiment and theme analysis of commentsAPI Key (Pro+)
GET/healthAPI status and versionNone

Extract Subtitles

POST/api/v1/extract

Extract subtitles from a YouTube video. Supports multiple languages and output formats (timed segments or plain text).

Request Body

ParameterTypeRequiredDescription
urlstringRequiredYouTube video URL. Supports youtube.com/watch, youtu.be, and youtube.com/shorts formats.
languagestringOptional(default: "en")ISO 639-1 language code for desired subtitle language.
include_timestampsbooleanOptional(default: true)When true, returns timed segments. When false, returns plain text.
force_refreshbooleanOptional(default: false)Bypass cache and fetch fresh subtitles from YouTube.
includestring[]Optional(default: [])Optional metadata fields to include. See Video Metadata section below.
formatstringOptional(default: "json")Output format. Options: json, srt, vtt, txt, md. See Output Formats section.
Example Requestbash
curl -X POST https://api.ytsubs.dev/api/v1/extract \
  -H "Content-Type: application/json" \
  -H "X-API-Key: yt_sub_your_api_key_here" \
  -d '{
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "language": "en",
    "include_timestamps": true,
    "include": ["description", "view_count"]
  }'

Response (Timed Mode)

When include_timestamps is true (default), subtitles are returned as an array of timed segments:

FieldTypeDescription
video_idstringYouTube video ID extracted from URL
metadataobjectVideo metadata (see Video Metadata section)
languagestringLanguage code of returned subtitles
subtitle_typestring"manual" (human-created) or "auto_generated"
subtitlesarrayArray of subtitle segments with timing
subtitles[].textstringText content of the segment
subtitles[].startnumberStart time in seconds
subtitles[].durationnumberDuration in seconds
cachedbooleanWhether response was served from cache
extracted_atstringISO 8601 timestamp of extraction
rate_limitobjectCurrent rate limit status (see below)
request_idstringUnique request identifier for support
Response (Timed Mode)json
{
  "video_id": "dQw4w9WgXcQ",
  "metadata": {
    "title": "Rick Astley - Never Gonna Give You Up",
    "channel": "Rick Astley",
    "channel_id": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "duration": 213,
    "upload_date": "20091025",
    "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
    "description": "The official video for...",
    "view_count": 1500000000
  },
  "language": "en",
  "subtitle_type": "manual",
  "subtitles": [
    {
      "text": "We're no strangers to love",
      "start": 18.0,
      "duration": 3.5
    },
    {
      "text": "You know the rules and so do I",
      "start": 21.5,
      "duration": 3.2
    }
  ],
  "cached": false,
  "extracted_at": "2024-01-15T10:30:00Z",
  "rate_limit": {
    "remaining": 99,
    "limit": 100,
    "reset": 1705363200
  },
  "request_id": "req_abc123"
}

Response (Plain Text Mode)

When include_timestamps is false, subtitles are returned as concatenated plain text:

FieldTypeDescription
video_idstringYouTube video ID extracted from URL
metadataobjectVideo metadata (see Video Metadata section)
languagestringLanguage code of returned subtitles
subtitle_typestring"manual" or "auto_generated"
textstringFull subtitle text without timestamps
segment_countnumberNumber of original segments combined
cachedbooleanWhether response was served from cache
extracted_atstringISO 8601 timestamp of extraction
rate_limitobjectCurrent rate limit status
request_idstringUnique request identifier
Response (Plain Text Mode)json
{
  "video_id": "dQw4w9WgXcQ",
  "metadata": {
    "title": "Rick Astley - Never Gonna Give You Up",
    "channel": "Rick Astley",
    "channel_id": "UCuAXFkgsw1L7xaCfnd5JJOw",
    "duration": 213,
    "upload_date": "20091025",
    "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg"
  },
  "language": "en",
  "subtitle_type": "manual",
  "text": "We're no strangers to love You know the rules and so do I...",
  "segment_count": 42,
  "cached": true,
  "extracted_at": "2024-01-15T10:30:00Z",
  "rate_limit": {
    "remaining": 98,
    "limit": 100,
    "reset": 1705363200
  },
  "request_id": "req_def456"
}

Output Formats

Use the format parameter to receive subtitles in different formats. The default is JSON.

FormatContent-TypeDescription
jsonapplication/jsonDefault. Full response with metadata and timing.
srttext/srtSubRip format. Compatible with most video players.
vtttext/vttWebVTT format. Native HTML5 video support.
txttext/plainPlain text. One line per segment, no timing.
mdtext/markdownMarkdown with optional timestamps. Great for AI/LLM input.

When to Use Each Format

  • JSON — API integrations, programmatic access, when you need metadata
  • SRT — Video editing software (Premiere, DaVinci), media players (VLC)
  • VTT — Web video players, HTML5 <track> element, streaming platforms
  • TXT — Search indexing, simple text processing, reading transcripts
  • MD — AI/LLM context, documentation, note-taking apps

Format Examples

SRT Formattext
1
00:00:18,000 --> 00:00:21,500
We're no strangers to love

2
00:00:21,500 --> 00:00:24,700
You know the rules and so do I
VTT Formattext
WEBVTT

00:00:18.000 --> 00:00:21.500
We're no strangers to love

00:00:21.500 --> 00:00:24.700
You know the rules and so do I
TXT Formattext
We're no strangers to love
You know the rules and so do I
A full commitment's what I'm thinking of
Markdown Format (with timestamps)markdown
# Rick Astley - Never Gonna Give You Up

**Channel:** Rick Astley
**Duration:** 3:33

## Transcript

[0:18] We're no strangers to love
[0:21] You know the rules and so do I
[0:25] A full commitment's what I'm thinking of

Markdown Timestamps: The include_timestamps parameter controls whether timestamps appear in Markdown output. Set to false for cleaner prose-style text.

AI Summary

POST/api/v1/summarize

Generate an AI-powered summary of a YouTube video using its transcript. Requires Pro or Business tier.

Credit Cost

This endpoint uses credits. Cost varies by video duration: 2 credits (≤10 min), 4 credits (10-30 min), 6 credits (30+ min). See Credits for details.

Request Body

ParameterTypeRequiredDescription
video_urlstringRequiredYouTube video URL to summarize.
stylestringOptional(default: "brief")Summary style: "brief" (concise paragraph), "detailed" (comprehensive), "key_points" (bullet list).
Example Requestbash
curl -X POST https://api.ytsubs.dev/api/v1/summarize \
  -H "Content-Type: application/json" \
  -H "X-API-Key: yt_sub_your_api_key_here" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "style": "key_points"
  }'

Response

FieldTypeDescription
summarystringAI-generated summary text
video_idstringYouTube video ID
credits_usednumberCredits charged (2, 4, or 6 based on duration)
cachedbooleanWhether served from cache (0 credits if you previously paid)
video_metadataobjectVideo title, duration, and channel
timestampsarrayStructured timestamps with topic labels (may be empty for short videos)
Responsejson
{
  "summary": "This video presents the classic 1987 hit 'Never Gonna Give You Up' by Rick Astley...",
  "video_id": "dQw4w9WgXcQ",
  "credits_used": 2,
  "cached": false,
  "video_metadata": {
    "title": "Rick Astley - Never Gonna Give You Up",
    "duration": 213,
    "channel": "Rick Astley"
  },
  "timestamps": [
    { "seconds": 0, "topic": "Introduction", "text": "Opening instrumental" },
    { "seconds": 18, "topic": "First Verse", "text": "Main chorus begins" }
  ]
}

Summary Styles

StyleDescription
briefConcise 2-3 sentence summary. Best for quick overviews.
detailedComprehensive paragraph covering main topics and key points.
key_pointsBullet-point list of key takeaways. Best for educational content.

Caching: Summaries are cached for 24 hours. If you request the same video again, you get the cached result at no additional cost. Different users requesting the same video are each charged once.

Comments Download

GET/api/v1/comments

Extract comments from a YouTube video. Supports up to 2,000 comments per request. Requires Pro or higher tier.

Credit Cost

1 credit per 500 comments (rounded up). Example: 501 comments = 2 credits. See Credits for details.

Query Parameters

ParameterTypeRequiredDescription
urlstringRequiredYouTube video URL.
maxnumberOptional(default: 500)Maximum comments to return (1-2000).
sortstringOptional(default: "relevance")Sort order: "relevance" (YouTube default) or "time" (newest first).
Example Requestbash
curl "https://api.ytsubs.dev/api/v1/comments?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ&max=100&sort=time" \
  -H "X-API-Key: yt_sub_your_api_key_here"

Response

FieldTypeDescription
commentsarrayArray of comment objects
comments[].authorstringComment author username
comments[].textstringComment text content
comments[].likesnumberNumber of likes on comment
comments[].published_atnumberUnix timestamp when published
comments[].is_replybooleanTrue if reply to another comment
video_idstringYouTube video ID
comment_countnumberNumber of comments returned
comments_disabledbooleanTrue if video has comments disabled
cachedbooleanWhether served from cache (0 credits)
credits_usednumberCredits charged for this request
request_idstringUnique request identifier
Responsejson
{
  "comments": [
    {
      "author": "MusicFan123",
      "text": "This song never gets old!",
      "likes": 1523,
      "published_at": 1609459200,
      "is_reply": false
    },
    {
      "author": "RetroLover",
      "text": "The 80s were the best era for music",
      "likes": 842,
      "published_at": 1612137600,
      "is_reply": false
    }
  ],
  "video_id": "dQw4w9WgXcQ",
  "comment_count": 100,
  "comments_disabled": false,
  "cached": false,
  "credits_used": 1,
  "request_id": "req_abc123"
}

Comments Disabled: If a video has comments disabled, the response returns an empty array with comments_disabled: true. No credits are charged in this case.

Comments Analysis

POST/api/v1/comments/analyze

AI-powered sentiment analysis of video comments. Identifies themes, sentiment, and extracts key representative quotes. Requires Pro or higher tier.

Credit Cost

Fixed 3 credits per analysis, regardless of comment count. Minimum 10 comments required.

Request Body

ParameterTypeRequiredDescription
video_urlstringRequiredYouTube video URL to analyze comments for.
sample_sizenumberOptional(default: 50)Number of comments to sample for analysis (10-100).
Example Requestbash
curl -X POST https://api.ytsubs.dev/api/v1/comments/analyze \
  -H "Content-Type: application/json" \
  -H "X-API-Key: yt_sub_your_api_key_here" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "sample_size": 50
  }'

Response

FieldTypeDescription
sentimentstringOverall sentiment: "positive", "negative", or "mixed"
themesarrayUp to 5 key themes identified in comments
key_quotesarrayUp to 10 representative quotes with author
key_quotes[].textstringThe comment text (may be truncated)
key_quotes[].authorstringComment author name
video_idstringYouTube video ID
sample_sizenumberActual number of comments analyzed
total_commentsnumberTotal comments available on video
credits_usednumberCredits charged (always 3, or 0 if cached)
cachedbooleanWhether served from cache
request_idstringUnique request identifier
Responsejson
{
  "sentiment": "positive",
  "themes": [
    "Nostalgia for 80s music",
    "Appreciation for the music video",
    "Rick Astley's vocal talent",
    "Internet meme culture",
    "Timeless appeal"
  ],
  "key_quotes": [
    {
      "text": "This song is genuinely great, meme status aside",
      "author": "MusicCritic42"
    },
    {
      "text": "The 80s really knew how to make music videos",
      "author": "RetroFan"
    }
  ],
  "video_id": "dQw4w9WgXcQ",
  "sample_size": 50,
  "total_comments": 2453,
  "credits_used": 3,
  "cached": false,
  "request_id": "req_xyz789"
}

Sampling Strategy: Comments are sampled using a balanced approach: 50% from top comments (by likes) and 50% from recent comments. This ensures analysis captures both popular sentiment and current reactions.

Batch Extraction

POST/api/v1/batch

Extract subtitles from multiple YouTube videos in a single request. Process up to 10 videos concurrently with partial success handling.

Credit Cost

1 credit per successful extraction. Failed extractions are free. Batch counts as 1 request toward your daily rate limit.

Request Body

ParameterTypeRequiredDescription
urlsstring[]RequiredArray of YouTube video URLs (1-10 URLs).
languagestringOptional(default: "en")ISO 639-1 language code for subtitles.
formatstringOptional(default: "json")Output format: json, srt, vtt, txt, or md.
include_timestampsbooleanOptional(default: true)Include timing data in output.
includestring[]Optional(default: [])Optional metadata fields to include.
Example Requestbash
curl -X POST https://api.ytsubs.dev/api/v1/batch \
  -H "Content-Type: application/json" \
  -H "X-API-Key: yt_sub_your_api_key_here" \
  -d '{
    "urls": [
      "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
      "https://youtu.be/9bZkp7q19f0"
    ],
    "language": "en",
    "format": "json"
  }'

Response

FieldTypeDescription
resultsarrayOne result per input URL (success or error)
results[].successbooleanTrue if extraction succeeded
results[].video_idstringYouTube video ID
results[].urlstringOriginal URL submitted
results[].subtitlesarraySubtitle segments (if success)
results[].error_codestringError code (if failed)
results[].error_messagestringError message (if failed)
credits_chargednumberTotal credits charged
credits_detailsobjectBreakdown: successful, failed, total_attempted
rate_limitobjectCurrent rate limit status
extracted_atstringISO8601 timestamp
Response (Partial Success)json
{
  "results": [
    {
      "success": true,
      "video_id": "dQw4w9WgXcQ",
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
      "subtitles": [{ "text": "...", "start": 0.0, "duration": 3.5 }],
      "language": "en",
      "metadata": { "title": "...", "channel": "...", "duration": 213 },
      "subtitle_type": "manual"
    },
    {
      "success": false,
      "url": "https://youtu.be/invalid123",
      "video_id": null,
      "error_code": "VIDEO_NOT_FOUND",
      "error_message": "Video not found or unavailable"
    }
  ],
  "credits_charged": 1,
  "credits_details": { "successful": 1, "failed": 1, "total_attempted": 2 },
  "rate_limit": { "limit": 10000, "remaining": 9999, "reset": 1705449600 },
  "extracted_at": "2024-01-16T10:30:00Z"
}

Timeout: Batch requests have a 60-second total timeout, distributed across videos. Partial results are returned even if some videos timeout.

Playlist Extraction

GET/api/v1/playlist

Extract subtitles from all videos in a YouTube playlist. Supports up to 25 videos per request with extended timeout.

Credit Cost

1 credit per successful extraction. Failed extractions are free. Playlist counts as 1 request toward your daily rate limit.

Query Parameters

ParameterTypeRequiredDescription
urlstringRequiredYouTube playlist URL.
maxnumberOptional(default: 10)Maximum videos to process (1-25).
languagestringOptional(default: "en")ISO 639-1 language code for subtitles.
formatstringOptional(default: "json")Output format: json, srt, vtt, txt, or md.
include_timestampsbooleanOptional(default: true)Include timing data in output.
includestringOptional(default: "")Comma-separated optional metadata fields.
Example Requestbash
curl "https://api.ytsubs.dev/api/v1/playlist?url=https://www.youtube.com/playlist?list=PLxxx&max=5&language=en" \
  -H "X-API-Key: yt_sub_your_api_key_here"

Response

FieldTypeDescription
playlistobjectPlaylist metadata
playlist.titlestringPlaylist title
playlist.uploaderstringChannel/uploader name
playlist.total_videosnumberTotal videos in playlist
extracted_countnumberNumber of videos processed
resultsarrayOne result per processed video
credits_chargednumberTotal credits charged
credits_detailsobjectBreakdown of successful/failed
rate_limitobjectCurrent rate limit status
extracted_atstringISO8601 timestamp
Responsejson
{
  "playlist": {
    "title": "My Music Playlist",
    "uploader": "MusicChannel",
    "total_videos": 50
  },
  "extracted_count": 5,
  "results": [
    {
      "success": true,
      "video_id": "dQw4w9WgXcQ",
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
      "subtitles": [{ "text": "...", "start": 0.0, "duration": 3.5 }],
      "language": "en",
      "metadata": { "title": "...", "channel": "...", "duration": 213 },
      "subtitle_type": "manual"
    }
  ],
  "credits_charged": 5,
  "credits_details": { "successful": 5, "failed": 0, "total_attempted": 5 },
  "rate_limit": { "limit": 10000, "remaining": 9999, "reset": 1705449600 },
  "extracted_at": "2024-01-16T10:30:00Z"
}

Extended Timeout: Playlist requests have a 120-second total timeout (vs 60s for batch) to accommodate larger video counts. Per-video timeout is calculated as max(120/video_count, 10) seconds.

Pre-flight Validation

GET/api/v1/validate

Check if subtitles are available for a video before extraction. This is a free, public endpoint — no authentication required, no rate limit impact.

Free & Public

No API key required. No credits charged. Does not count toward your rate limit. Response cached for 1 hour.

Query Parameters

ParameterTypeRequiredDescription
urlstringRequiredYouTube video URL to validate.
Example Requestbash
curl "https://api.ytsubs.dev/api/v1/validate?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ"

Response

FieldTypeDescription
validbooleanTrue if URL is a valid YouTube video
has_subtitlesbooleanTrue if any subtitles are available
available_languagesobjectAvailable subtitle languages
available_languages.manualstring[]Human-created subtitle languages (ISO 639-1)
available_languages.auto_generatedstring[]Auto-generated subtitle languages
video_titlestringVideo title
durationnumberVideo duration in seconds
cachedbooleanWhether response was served from cache
Responsejson
{
  "valid": true,
  "has_subtitles": true,
  "available_languages": {
    "manual": ["en", "es"],
    "auto_generated": ["en", "de", "fr", "ja", "pt", "zh"]
  },
  "video_title": "Rick Astley - Never Gonna Give You Up",
  "duration": 213,
  "cached": false
}

Use Cases

  • URL Validation — Verify URLs before adding to a batch
  • Language Discovery — Check available languages before extraction
  • UI Display — Show video info and subtitle availability in your app
  • Cost Estimation — Preview which videos will succeed before committing credits

Video Metadata

Every response includes a metadata object with video information. Some fields are always included, while others are opt-in via the include parameter.

Always-On Fields

These 6 fields are always included in the metadata object:

FieldTypeDescription
titlestringVideo title
channelstringChannel name
channel_idstringYouTube channel ID
durationnumberVideo duration in seconds
upload_datestringUpload date in YYYYMMDD format
thumbnail_urlstringURL to video thumbnail image

Opt-In Fields

Request additional fields using the include array. Only requested fields will appear in the response:

FieldTypeDescription
descriptionstringFull video description text
tagsstring[]Video tags set by the uploader
categoriesstring[]YouTube category names
view_countnumberTotal view count
like_countnumberNumber of likes
comment_countnumberNumber of comments
chaptersobject[]Video chapters with title and start_time
is_livebooleanTrue if video is currently live streaming
was_livebooleanTrue if video was a live stream
Example: Requesting Opt-In Fieldsbash
curl -X POST https://api.ytsubs.dev/api/v1/extract \
  -H "Content-Type: application/json" \
  -H "X-API-Key: yt_sub_your_api_key_here" \
  -d '{
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "include": ["description", "view_count", "like_count", "tags"]
  }'

Note: Invalid field names in the include array will return a 400 Bad Request error with the list of valid fields.

Rate Limiting

API requests are rate-limited based on your subscription tier. Rate limit information is included in both response headers and body.

Response Headers

FieldTypeDescription
X-RateLimit-LimitnumberMaximum requests allowed per day
X-RateLimit-RemainingnumberRequests remaining in current period
X-RateLimit-ResetstringISO 8601 timestamp when limit resets

Rate Limit Object

Each successful response includes a rate_limit object:

{
  "rate_limit": {
    "remaining": 99,
    "limit": 100,
    "reset_at": "2024-01-16T00:00:00Z"
  }
}

Tier Limits

TierDaily LimitReset Time
Free100 requestsMidnight UTC
Pro10,000 requestsMidnight UTC
EnterpriseUnlimited

Rate Limit Exceeded

When you exceed your rate limit, requests return a 429 Too Many Requests error. See the error reference for details.

HTTP Status Codes

StatusDescription
200 OKSubtitles extracted successfully
400 Bad RequestInvalid request body or parameters
401 UnauthorizedMissing or invalid API key
404 Not FoundVideo not found or no subtitles available
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorServer error (include request_id when reporting)

See the error reference for detailed error codes and troubleshooting.