# Capslane documentation

Capslane retrieves transcripts from public YouTube videos. Use native captions or let auto mode generate a transcript when no usable caption track is available.

Using Claude Code, Codex or Cursor? [Install the transcript skill](https://capslane.com/integrations/agent-skill#install) or [connect the MCP tools](https://capslane.com/integrations/mcp). Claude Code has a [plugin that installs both](https://capslane.com/integrations/mcp#claude-code).

## Authentication and first request

Create a server key from [API Keys](https://capslane.com/api-keys). Store it in CAPSLANE_API_KEY in your server environment. Never put it in browser code or source control. The production base URL is https://capslane.com; every public API call uses the x-api-key header.

This Bash example requires curl 7.76 or later. Native mode never starts generation. In PowerShell, use curl.exe and $env:CAPSLANE_API_KEY instead of Bash variable syntax.

```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"
```

## Node.js quickstart

Install with npm install @webba_tech/capslane. Save this as transcript-sdk.mjs and run node transcript-sdk.mjs with Node.js 22 or later.

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.

```js
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
}
```

The shared abort signal bounds requests and waits. The [Node.js guide](https://capslane.com/guides/youtube-transcript-api-nodejs) includes the HTTP alternative and output handling.

### Resume a saved job in Node.js

client.transcriptJob(jobId, signal) takes an AbortSignal directly as its second argument. client.waitForTranscript(jobId, { signal }) takes an options object.

SDK 0.1.4 exports importTranscript and resumeTranscript from @webba_tech/capslane/workflows. The [complete Node import](https://capslane.com/examples/import-transcript.mjs) returns { url, transcript, timestampedText }; original segments are in transcript.content. The [complete MCP client](https://capslane.com/examples/import-transcript-mcp.mjs) unwraps structuredContent before using content and status. Both await a job record with its video URL before polling and preserve jobId on errors.

The [resume module](https://capslane.com/examples/resume-transcript.mjs) polls the saved ID with a shared deadline, preserves jobId and requestId on errors, and stops on completed without content. Read the [usage example](https://capslane.com/guides/youtube-transcript-api-nodejs#resume). Its submitTranscript function awaits your saveJob callback before returning; storage errors retain the accepted ID. Its resumeTranscript function never submits the video again.

## Python quickstart

Install with python -m pip install capslane. Save this as transcript_sdk.py and run python transcript_sdk.py with Python 3.10 or later.

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.

```python
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
```

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.

The Python example allows 45 seconds per call and a twenty-minute polling window. The [Python HTTP alternative](https://capslane.com/guides/youtube-transcript-api-python#http) uses a shared deadline.

## Use with a coding assistant

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](https://github.com/Webba-Creative-Technologies/capslane-js/blob/main/docs/client.md) and [Python method reference](https://github.com/Webba-Creative-Technologies/capslane-python/blob/main/docs/client.md) document exact signatures and timeout defaults. Their [HTTP response examples](https://github.com/Webba-Creative-Technologies/capslane-js/blob/main/docs/http-contract.md) cover completed, failed and expired jobs.

For retrieval applications, the [LangChain guide](https://capslane.com/integrations/langchain.md) covers the optional Python document loader, local chunking, playback citations and executable passage search.

Install the [Capslane agent skill](https://capslane.com/integrations/agent-skill) to give Codex, Claude Code or Cursor a transcript workflow with timestamps and bounded job polling. The [skill instructions](https://capslane.com/skills/capslane-youtube-transcripts/SKILL.md) describe the MCP and bundled HTTP paths. Installation commands and all supporting files are linked from the guide.

| Language | Context7 library ID |
| --- | --- |
| JavaScript and TypeScript | [/webba-creative-technologies/capslane-js](https://context7.com/webba-creative-technologies/capslane-js) |
| Python | [/webba-creative-technologies/capslane-python](https://context7.com/webba-creative-technologies/capslane-python) |

Once Context7 is connected to your assistant, try this request:

```text
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](https://capslane.com/integrations/mcp). You can also provide [this Markdown page](https://capslane.com/docs.md), the [Markdown API reference](https://capslane.com/api-reference.md) or [OpenAPI JSON](https://capslane.com/openapi.json) directly. The [documentation index](https://capslane.com/llms.txt) lists the public sources. Keep API keys out of your prompts.

## Modes and cache

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.

| Mode | On a cache miss |
| --- | --- |
| native | Fetch a native caption track. Never start audio generation. Return transcript_unavailable if no usable track exists. |
| auto | Try native captions, then start generation only after transcript_unavailable. A temporary upstream failure remains an error. |
| generate | Start or reuse an asynchronous generation job without first trying native extraction. |

## Responses and jobs

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.

A ready transcript returns HTTP 200:

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

An accepted generation returns HTTP 202:

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

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.

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.

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.

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

## Errors, timeouts and quotas

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.

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.

API request errors include error, message and requestId. Failed or cancelled jobs may carry an error code without a message. Network and proxy failures can occur before an API JSON response exists. See [errors and retries](https://capslane.com/guides/youtube-transcript-api-errors).

## Reference and tools

The [API reference](https://capslane.com/api-reference.md) describes parameters, account checks and job responses. [OpenAPI JSON](https://capslane.com/openapi.json) defines request and response schemas. The HTML documentation is at [docs](https://capslane.com/docs).

Inspect native captions with the [Transcript Inspector](https://capslane.com/youtube-transcript-inspector). See the [reliability methodology](https://capslane.com/reliability/methodology), [guides](https://capslane.com/guides) and [pricing](https://capslane.com/pricing) for further details.
