# Capslane API reference

Base URL: https://capslane.com. Authenticate with x-api-key on every call. Create or revoke keys in [API Keys](https://capslane.com/api-keys). A dashboard session cookie does not authenticate public API requests.

## GET /v1/account

Validate a key without reserving a transcript unit. The response contains workspace (name), plan and monthlyLimit. There is no account method in the current Python or JavaScript SDK; call HTTP directly.

```bash
curl --fail-with-body "https://capslane.com/v1/account" --header "x-api-key: $CAPSLANE_API_KEY"
```

## GET /v1/transcript

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| url | string | Required | An 11-character video ID or HTTPS YouTube watch, Shorts or youtu.be URL. |
| lang | string | Source selection | Preferred language: 2 or 3 letters, optionally followed by a 2-letter region, such as en or fr-FR. |
| mode | enum | auto | native, auto or generate. Applied after cache lookup. |
| text | boolean | false | Return one string in an immediate response. Job results remain segmented. |
| chunkSize | integer | Original segments | Character budget from 50 to 10,000 for grouping whole segments in an immediate response. |

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. |

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.

### HTTP 200

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

With text=true, content is a string in this immediate response. source is native or generated; cached indicates reuse. requestId identifies this request in Logs.

### HTTP 202

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

Use jobId to construct the status URL. The response does not include a separate job URL. Progress is optional.

## 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 or cancelled, 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 accepted jobId. This Bash command checks once; it is not a polling loop.

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

States are queued, downloading, processing, persisting, completed, failed and cancelled. Successful status checks return HTTP 200, including intermediate and failed jobs.

### Completed job

```json
{
  "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"
}
```

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.

### Failed job

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

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.

If a completed state has no content, stop when your deadline expires and investigate the stored result; do not wait forever.

## Errors

API request errors use this envelope:

```json
{
  "error": "invalid_video_id",
  "message": "The YouTube video ID is invalid",
  "requestId": "req_example"
}
```

| HTTP | Code | Meaning and action |
| --- | --- | --- |
| 400 | invalid_request | A header, query or job ID fails validation. A missing or too-short x-api-key header also returns this code. |
| 400 | invalid_video_id | The video URL or identifier is invalid. Correct the input. |
| 401 | invalid_api_key | The supplied key is invalid, expired or revoked. |
| 404 | transcript_unavailable | No usable native track exists. Consider auto only if generation is permitted. |
| 404 | job_not_found | The job is absent or belongs to another workspace. |
| 429 | request_failed | Short rate limit. Respect Retry-After before trying again. |
| 429 | monthly_limit_exceeded | The monthly transcript request allowance is exhausted. |
| 429 | generation_minutes_limit_exceeded | The Free generated-minute allowance cannot cover this generation. |
| 429 | generation_concurrency_exceeded | The Free workspace already has an active generation. |
| 502 | upstream_unavailable | The upstream service could not complete the request. Use bounded backoff. |
| 503 | capacity_exceeded | The generation queue is full. Try again later within a retry budget. |

These are common API errors, not an exhaustive list of upstream failures. A worker can return other codes, such as video_unavailable. Network and proxy errors may not include JSON. SDK processing_timeout describes a local wait timeout; it does not prove a server job failed.

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.

## Limits and accounting

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.

See [pricing](https://capslane.com/pricing), the [integration walkthrough](https://capslane.com/docs.md) and [OpenAPI JSON](https://capslane.com/openapi.json). The HTML reference is at [api-reference](https://capslane.com/api-reference).
