API Documentation
Archivarix Tube Search provides a REST API for programmatic access to archived YouTube video metadata, subtitles, and AI summaries. This page is the complete API reference.
API access requires the Pro subscription tier. See Pricing for details.
Authentication
API keys are created in your Profile → API tab. Include the key in every request using one of these headers:
X-API-Key: tsk_YOUR_KEY_HERE
or
Authorization: Bearer tsk_YOUR_KEY_HERE
Keys use the tsk_ prefix. Keep your key secret — it grants full API access to your account.
Endpoints
Search (Channel Search via SSE)
Channel search is a two-step process: create a search session, then consume results via Server-Sent Events.
POST /api/search
Start a new channel search.
Request body (JSON):
{
"query": "@handle or channel URL or video URL/ID"
}
Response:
{
"data": {
"searchSessionId": "uuid",
"sseEndpointUrl": "/api/search/uuid/stream",
"channelId": "UCxxxxxx",
"channelTitle": "Channel Name"
}
}
GET /api/search/:sessionId/stream
Connect to the SSE stream to receive search results in real time. Set the Accept: text/event-stream header. See the SSE Protocol section below for event types.
POST /api/search/:sessionId/continue
Continue a paginated search to load the next page of archive results. Returns a new SSE stream URL.
GET /api/search/background-status/:channelId
Check if a channel search is currently running in the background.
Response:
{
"data": {
"running": true,
"searchSessionId": "uuid"
}
}
Full-Text Search
GET /api/fts
Search across all indexed video titles and descriptions.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
q | string | Search query (required) |
page | number | Page number (default: 1) |
pageSize | number | Results per page (default: 50, max: 100) |
status | string | Filter: deleted or live |
hasVideo | boolean | Only videos with archived video files |
hasSubtitles | boolean | Only videos with subtitles |
hasSummary | boolean | Only videos with AI summaries |
sort | string | relevance | date-desc | date-asc | duration-desc | duration-asc |
Subtitles
GET /api/subtitles/:videoId
Download subtitles for a video.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
format | string | srt (default) or vtt |
POST /api/subtitles/:videoId/fetch
Fetch subtitles on demand. Triggers a background job if subtitles are not yet available.
POST /api/subtitles/bulk-download
Download subtitles for multiple videos at once.
Request body (JSON):
{
"videoIds": ["dQw4w9WgXcQ", "jNQXAC9IVRw"],
"query": "optional highlight query"
}
AI Summaries
POST /api/summary/generate
Generate an AI summary for a video. Requires available subtitles.
Request body (JSON):
{
"videoId": "dQw4w9WgXcQ",
"private": false
}
Response (202 Accepted):
{
"data": {
"status": "generating",
"videoId": "dQw4w9WgXcQ"
}
}
GET /api/summary/:videoId
Get the AI summary for a specific video.
DELETE /api/summary/:videoId
Delete a summary. Admin only.
GET /api/summary/browse
Browse summaries with filters.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
tag | string | Filter by tag |
channelId | string | Filter by channel |
language | string | Filter by language code |
page | number | Page number (default: 1) |
limit | number | Results per page (default: 20) |
GET /api/summary/latest
Get the most recently generated summaries.
GET /api/summary/tags
Get popular tags across all summaries.
GET /api/summary/languages
Get available summary languages with counts.
GET /api/summary/channels
Get channels that have summaries.
AI Stenograms (L3+)
Stenogram endpoints require an API key with L3+ scope. Stenograms are private to the owner and never appear in public listings or sitemaps. See AI Stenograms for the privacy model.
POST /api/stenograms/:videoId/generate
Generate a private stenogram (full-text dialogue with speaker tags) from a completed transcript. Streams progress via Server-Sent Events.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
videoId | string | YouTube video ID (11 characters) |
Request body (JSON, optional):
{
"language": "en"
}
language is an optional ISO 639-1/639-2 hint (e.g. en, ru, en-US). Omit for auto-detect.
Response: SSE stream with progress events, ending in a stenogram:complete event whose payload contains { stenogram, metadata }. On error: standard JSON error envelope (e.g. FEATURE_DISABLED, RATE_LIMITED, TRANSCRIPT_REQUIRED, STENOGRAM_CONFLICT).
Counter: apiStenogramsPerDay (per-key, resets at midnight UTC; shared with the MCP generate_stenogram tool).
GET /api/stenograms/@:userId/:videoId
Read your own stenogram as raw Markdown. Returns 404 to anyone but the owner.
GET /api/stenograms/@:userId/:videoId/meta
Get stenogram metadata as JSON: { videoId, title, channelTitle, channelId, language, tokensUsed, llmModel, generatedAt }.
GET /api/user/stenograms
Paginated listing of stenograms owned by the authenticated user. Supports ?page=N; page size is 20.
GET /api/user/stenograms/video-ids
Bulk existence — returns the YouTube IDs of every stenogram the caller owns (capped at 1000). Used by the web UI to render View vs Generate state per row in a single round-trip.
DELETE /api/stenograms/@:userId/:videoId
Permanently delete your stenogram. Removes the database row and the stored Markdown file. No soft-delete.
Video Status
GET /api/videos/:videoId/status-history
Get the status change history for a video (e.g., live → deleted → re-uploaded).
System
GET /api/health
Health check endpoint. Returns server status.
GET /api/features
Get feature flags and limits for the current user/tier.
GET /api/tiers
Get tier comparison data (limits, features per tier).
SSE Protocol
The channel search stream sends Server-Sent Events. Each event has a type and JSON data payload:
| Event | Description |
|---|---|
search:channel_resolved | Channel info resolved (channelId, title, avatar, etc.) |
search:progress | Pipeline progress update (stage name, percentage) |
search:video | Individual video result |
search:video_batch | Batch of video results (more efficient) |
search:caption_info | Subtitle availability info for discovered videos |
search:complete | Search completed successfully |
search:error | Error occurred during search |
Rate Limits
API requests (Pro tier) have the following rate limits:
When a limit is exceeded, the API returns HTTP 429 with the RATE_LIMITED error code.
Error Codes
All errors return JSON with an error object:
{"error": {"code": "RATE_LIMITED", "message": "Rate limit exceeded"}}
| Code | Meaning |
|---|---|
UNAUTHORIZED | Missing or invalid API key |
FORBIDDEN | API access not enabled for your account |
RATE_LIMITED | Rate limit exceeded |
API_KEY_REQUIRED | Programmatic access requires an API key |
INVALID_INPUT | Invalid query or parameters |
NOT_FOUND | Resource not found |
Examples
curl
# Start a channel search
curl -X POST https://tube.archivarix.net/api/search \
-H "X-API-Key: tsk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "@MrBeast"}'
# Stream results (SSE)
curl -N https://tube.archivarix.net/api/search/SESSION_ID/stream \
-H "X-API-Key: tsk_YOUR_KEY" \
-H "Accept: text/event-stream"
# Continue paginated search
curl -X POST https://tube.archivarix.net/api/search/SESSION_ID/continue \
-H "X-API-Key: tsk_YOUR_KEY"
# Full-text search
curl "https://tube.archivarix.net/api/fts?q=deleted+video&pageSize=20&sort=relevance" \
-H "X-API-Key: tsk_YOUR_KEY"
# Download subtitles (SRT)
curl https://tube.archivarix.net/api/subtitles/dQw4w9WgXcQ \
-H "X-API-Key: tsk_YOUR_KEY"
# Download subtitles (VTT)
curl "https://tube.archivarix.net/api/subtitles/dQw4w9WgXcQ?format=vtt" \
-H "X-API-Key: tsk_YOUR_KEY"
# Fetch subtitles on-demand
curl -X POST https://tube.archivarix.net/api/subtitles/dQw4w9WgXcQ/fetch \
-H "X-API-Key: tsk_YOUR_KEY"
# Generate AI summary
curl -X POST https://tube.archivarix.net/api/summary/generate \
-H "X-API-Key: tsk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"videoId": "dQw4w9WgXcQ"}'
# Get a summary
curl https://tube.archivarix.net/api/summary/dQw4w9WgXcQ \
-H "X-API-Key: tsk_YOUR_KEY"
# Browse summaries by tag
curl "https://tube.archivarix.net/api/summary/browse?tag=music&limit=10" \
-H "X-API-Key: tsk_YOUR_KEY"
# Health check
curl https://tube.archivarix.net/api/health
Python
import requests
API_KEY = "tsk_YOUR_KEY"
BASE = "https://tube.archivarix.net"
headers = {"X-API-Key": API_KEY}
# --- Channel search ---
resp = requests.post(f"{BASE}/api/search",
headers=headers,
json={"query": "@MrBeast"})
session = resp.json()["data"]
search_id = session["searchSessionId"]
# Stream results (SSE)
with requests.get(f"{BASE}/api/search/{search_id}/stream",
headers={**headers, "Accept": "text/event-stream"},
stream=True) as r:
for line in r.iter_lines(decode_unicode=True):
if line.startswith("data:"):
print(line[5:])
# --- Full-text search ---
resp = requests.get(f"{BASE}/api/fts",
headers=headers,
params={"q": "deleted video", "pageSize": 20, "sort": "relevance"})
print(resp.json())
# --- Download subtitles ---
resp = requests.get(f"{BASE}/api/subtitles/dQw4w9WgXcQ",
headers=headers,
params={"format": "srt"})
with open("subtitles.srt", "w") as f:
f.write(resp.text)
# --- Generate AI summary ---
resp = requests.post(f"{BASE}/api/summary/generate",
headers=headers,
json={"videoId": "dQw4w9WgXcQ"})
print(resp.json()) # {"data": {"status": "generating", ...}}
# --- Get summary ---
resp = requests.get(f"{BASE}/api/summary/dQw4w9WgXcQ",
headers=headers)
summary = resp.json()["data"]
print(summary["title"], summary["tags"])
JavaScript (Node.js / Browser)
const API_KEY = "tsk_YOUR_KEY";
const BASE = "https://tube.archivarix.net";
const headers = { "X-API-Key": API_KEY };
// --- Channel search ---
const searchResp = await fetch(`${BASE}/api/search`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ query: "@MrBeast" }),
});
const { data: { searchSessionId } } = await searchResp.json();
// Stream results (SSE)
const es = new EventSource(
`${BASE}/api/search/${searchSessionId}/stream`
);
es.addEventListener("search:video", (e) => {
const video = JSON.parse(e.data);
console.log(video.title, video.videoId);
});
es.addEventListener("search:complete", () => es.close());
// --- Full-text search ---
const ftsResp = await fetch(
`${BASE}/api/fts?q=deleted+video&pageSize=20`,
{ headers }
);
const results = await ftsResp.json();
// --- Download subtitles ---
const subResp = await fetch(
`${BASE}/api/subtitles/dQw4w9WgXcQ?format=srt`,
{ headers }
);
const srtText = await subResp.text();
// --- Generate AI summary ---
const sumResp = await fetch(`${BASE}/api/summary/generate`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ videoId: "dQw4w9WgXcQ" }),
});
console.log(await sumResp.json());
// --- Browse summaries ---
const browseResp = await fetch(
`${BASE}/api/summary/browse?tag=music&limit=10`,
{ headers }
);
console.log(await browseResp.json());