Introduction

Capslane provides one API for retrieving YouTube captions and generating transcripts when captions are unavailable.

Using Claude Code, Codex or Cursor? Install the transcript skill or connect the MCP tools. Claude Code also has a plugin that installs both.

Overview

Capslane checks the cache before applying the requested mode. A cached result can come from native captions or audio generation in any mode. Check source and cached in the response; mode controls what happens on a cache miss.

ModeOn a cache miss
nativeFetch a native caption track. Never start audio generation. Return transcript_unavailable if no usable track exists.
autoTry native captions, then start generation only after transcript_unavailable. A temporary upstream failure remains an error.
generateStart or reuse an asynchronous generation job without first trying native extraction.

Get an API key

Open your workspace, then create a server key in API Keys. Copy it immediately; the complete key is shown only once. Store it as CAPSLANE_API_KEY in your server environment.

Keep it server-side

Do not commit the key or expose it in browser and mobile bundles.

Authentication

Send the workspace API key in the x-api-key header on every request.

This first request uses native mode and never starts generation. These commands use Bash syntax and curl 7.76 or later. In PowerShell, use curl.exe and $env:CAPSLANE_API_KEY.

Bash
curl --fail-with-body --get "https://capslane.com/v1/transcript" \
  --header "x-api-key: $CAPSLANE_API_KEY" \
  --data-urlencode "url=dQw4w9WgXcQ" \
  --data-urlencode "mode=native"

The production base URL is https://capslane.com. A dashboard session cookie does not authenticate the public API.

Node.js quickstart

GET /v1/transcript returns HTTP 200 with content as a segment array by default, or a string when text=true. An accepted generation returns HTTP 202 with jobId, status and requestId, without content. Both SDK transcript methods return these same response bodies. Read content first, then retain jobId if generation was accepted.

Install
npm install @webba_tech/capslane
transcript-sdk.mjs
import { CapslaneClient, CapslaneError } from '@webba_tech/capslane'

const apiKey = process.env.CAPSLANE_API_KEY
if (!apiKey) throw new Error('Set CAPSLANE_API_KEY')
const client = new CapslaneClient({ apiKey, timeoutMs: 45_000 })
const signal = AbortSignal.timeout(20 * 60_000)

try {
  let result = await client.transcript({ url: 'dQw4w9WgXcQ', mode: 'auto', signal })
  if (!('content' in result)) {
    console.error('Accepted job:', result.jobId)
    result = await client.waitForTranscript(result, { signal })
  }
  console.log(JSON.stringify(result, null, 2))
} catch (error) {
  if (error instanceof CapslaneError) {
    console.error(error.status, error.code, error.requestId)
  }
  throw error
}

Use Node.js 22 or later and run node transcript-sdk.mjs. The shared abort signal bounds requests and waits. Download the example or read the Node.js guide for direct HTTP calls.

Python quickstart

GET /v1/transcript returns HTTP 200 with content as a segment array by default, or a string when text=true. An accepted generation returns HTTP 202 with jobId, status and requestId, without content. Both SDK transcript methods return these same response bodies. Read content first, then retain jobId if generation was accepted.

Install
python -m pip install capslane
transcript_sdk.py
import json
import os
import sys

from capslane import CapslaneClient, CapslaneError

client = CapslaneClient(api_key=os.environ["CAPSLANE_API_KEY"], timeout=45)

try:
    result = client.transcript("dQw4w9WgXcQ", mode="auto")
    if "content" not in result:
        print("Accepted job:", result["jobId"], file=sys.stderr)
        result = client.wait_for_transcript(result, timeout=20 * 60)
    print(json.dumps(result, indent=2))
except CapslaneError as error:
    print(error.code, error.status, error.request_id, file=sys.stderr)
    raise

Use Python 3.10 or later and run python transcript_sdk.py. This example allows 45 seconds per call and a twenty-minute polling window. Download the example; the Python HTTP alternative provides a shared deadline.

Stopping a client request or reaching a client timeout does not cancel an accepted server job. Resume with its job ID. JavaScript SDK 0.1.3 bounds both waits and in-flight reads within the polling deadline. Python checks its polling deadline between iterations. Each HTTP request also has its own timeout.

Use with a coding assistant

Building a retrieval or question-answering application? The LangChain integration loads timestamped Documents through the Python SDK.

Install the Capslane agent skill to give Codex, Claude Code or Cursor a workflow for retrieving transcripts, following jobs and citing timestamps. It uses an existing MCP connection or the bundled HTTP helper.

Use Context7 to look up the Capslane SDK before writing an integration. Give your assistant the library ID for your language so it can retrieve the right documentation.

The maintained JavaScript method reference and Python method reference document exact signatures and timeout defaults. Their HTTP response examples cover completed, failed and expired jobs.

LanguageContext7 library ID
JavaScript and TypeScript/webba-creative-technologies/capslane-js
Python/webba-creative-technologies/capslane-python

Open the JavaScript reference or Python reference in Context7. Once Context7 is connected to your assistant, try this request:

Prompt
Use the Capslane Python SDK to retrieve a YouTube transcript. Fetch its documentation from Context7 with library ID /webba-creative-technologies/capslane-python. Handle immediate results and accepted jobs, and keep the API key in an environment variable.

Context7 supplies documentation. To let an assistant call the transcript service, connect the Capslane MCP server with the setup for Claude Code, Codex or Cursor. See how Context7 indexes documentation for details about its sources.

You can also provide this page in Markdown, the Markdown API reference or OpenAPI JSON directly. The documentation index lists the public sources. Keep API keys out of your prompts.

GET

/v1/transcript

GET /v1/transcript returns HTTP 200 with content as a segment array by default, or a string when text=true. An accepted generation returns HTTP 202 with jobId, status and requestId, without content. Both SDK transcript methods return these same response bodies. Read content first, then retain jobId if generation was accepted.

Query parameters

ParameterTypeDefaultDescription
urlstringRequiredAn 11-character video ID or HTTPS YouTube watch, Shorts or youtu.be URL.
langstringSource selectionPreferred language: 2 or 3 letters, optionally followed by a 2-letter region, such as en or fr-FR.
modeenumautonative, auto or generate. Applied after cache lookup.
textbooleanfalseReturn one string in an immediate response. Job results remain segmented.
chunkSizeintegerOriginal segmentsCharacter budget from 50 to 10,000 for grouping whole segments in an immediate response.

lang is a preference, not a translation request. Inspect lang for the selected language and availableLangs for the tracks reported by the source.

Immediate responses support text=true for one string, or timestamped segments by default. Segment offsets and durations are milliseconds. chunkSize groups whole segments using a character budget from 50 to 10,000; an individual source segment can exceed that budget. text=true takes precedence over chunkSize.

200 response

JSON
{
  "content": [
    {
      "text": "Example segment.",
      "offset": 8150,
      "duration": 1200,
      "lang": "en"
    }
  ],
  "lang": "en",
  "availableLangs": [
    "en"
  ],
  "source": "native",
  "cached": false,
  "requestId": "req_example"
}

202 response

A generation job was accepted. Retain its jobId and follow the status endpoint below.

JSON
{
  "jobId": "job_550e8400-e29b-41d4-a716-446655440000",
  "status": "queued",
  "requestId": "req_example"
}
GET

/v1/transcript/:jobId

Poll GET /v1/transcript/{jobId} with a key from the same workspace. HTTP 200 can contain a pending or failed job. Wait for content, stop on failed, cancelled or completed without content, and set a deadline. Progress is optional. Keep the accepted job ID to resume waiting without submitting another transcript request.

Set CAPSLANE_JOB_ID to the returned ID. This command checks once.

Bash
curl --fail-with-body "https://capslane.com/v1/transcript/$CAPSLANE_JOB_ID" \
  --header "x-api-key: $CAPSLANE_API_KEY"

For Node.js, use the saved-job example. It preserves the ID across interruptions and stops when a completed job has no stored content.

The public job endpoint returns canonical timestamped segments when complete. It does not reapply text or chunkSize from the initial request. Join the returned segment text locally if you need one string. A completed response also has jobId, so use content to recognize a ready transcript.

Completed job, HTTP 200
{
  "content": [
    {
      "text": "Example segment.",
      "offset": 8150,
      "duration": 1200,
      "lang": "en"
    }
  ],
  "lang": "en",
  "availableLangs": [
    "en"
  ],
  "source": "generated",
  "cached": true,
  "requestId": "req_example",
  "jobId": "job_550e8400-e29b-41d4-a716-446655440000",
  "status": "completed"
}

Errors

API request errors include error, message and requestId. A failed job may contain an error code without a message. Network and proxy failures may not return JSON.

HTTPCodeMeaning and action
400invalid_requestA header, query or job ID fails validation. A missing or too-short x-api-key header also returns this code.
400invalid_video_idThe video URL or identifier is invalid. Correct the input.
401invalid_api_keyThe supplied key is invalid, expired or revoked.
404transcript_unavailableNo usable native track exists. Consider auto only if generation is permitted.
404job_not_foundThe job is absent or belongs to another workspace.
429request_failedShort rate limit. Respect Retry-After before trying again.
429monthly_limit_exceededThe monthly transcript request allowance is exhausted.
429generation_minutes_limit_exceededThe Free generated-minute allowance cannot cover this generation.
429generation_concurrency_exceededThe Free workspace already has an active generation.
502upstream_unavailableThe upstream service could not complete the request. Use bounded backoff.
503capacity_exceededThe generation queue is full. Try again later within a retry budget.

For a short rate limit, HTTP 429 uses request_failed with a Retry-After header. Monthly request and generated-minute limits require an allowance change or monthly reset. A concurrency limit can clear when the active generation finishes. Retry temporary upstream or capacity failures with bounded backoff; when polling, retry the same job ID.

See the error handling guide for retry decisions.

Monitor the workspace

The Overview shows monthly usage, success rate, cache rate, latency and recent API activity.

Capslane Overview with usage metrics and request chart
Overview keeps usage and service health in one place.

Test a request

The Playground runs through the server, so you can inspect the real response without exposing an API key in the browser.

Capslane Playground request form and JSON response panel
Choose the language, mode and output format before sending a request.

Limits and billing

A transcript request reserves one monthly unit before extraction and cache lookup. A cache hit uses one unit, and a later extraction failure can still consume that unit. Repeating the initial request can consume another unit. Job status and account checks do not reserve transcript units. A request rejected for an exhausted monthly allowance adds no unit.

Transcript submission and job status endpoints each allow 120 requests per minute per client IP. Account checks allow 60. Free workspaces include 50 transcript requests and 15 generated minutes per month, with one active generation at a time. Check the pricing page for current plan allowances.

NextView plans