tscaps.docs
Documentation

Automation API

Create captioned videos programmatically from your product or workflow.

The tscaps automation API lets you generate videos with burned-in captions programmatically. Submit a video source and a caption template, track processing progress, and download the finished video file.

All rendering and subtitle burn-in runs on our cloud infrastructure, powered by the same typography and animation engine as the tscaps Studio editor.

Building with AI coding agents?

You can equip your AI assistant (Cursor, Claude Code, GitHub Copilot, Windsurf, etc.) with the complete API specification or install our official skill:

  • Full documentation dump: llms-full.txt (single markdown file containing all endpoint schemas and parameters).
  • Documentation map: llms.txt (structured index per llmstxt.org).
  • Official Agent Skill (tscaps-api): Install via npx skills add francozanardi/tscaps --skill tscaps-api or inspect SKILL.md on GitHub.

Authentication

All requests to the Automation API require an API key. Pass your secret key in the Authorization header as a Bearer token:

Authorization: Bearer TSCAPS_API_KEY

You can generate and manage keys in your API keys dashboard. Keep your keys secure and do not expose them in client-side code.

The API base URL is:

https://api.tscaps.io

Quickstart

Follow these three steps to submit your first video, track rendering progress, and retrieve the finished output.

1. Start a job

Send a POST request to /v1/automation-jobs with a publicly accessible video URL and the ID of the template you want to apply.

curl -X POST https://api.tscaps.io/v1/automation-jobs \
  -H "Authorization: Bearer $TSCAPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "videoUrl": "https://example.com/reel.mp4",
    "templateId": "mira"
  }'
const response = await fetch("https://api.tscaps.io/v1/automation-jobs", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TSCAPS_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    videoUrl: "https://example.com/reel.mp4",
    templateId: "mira",
  }),
});

const job = await response.json();
console.log(`Job queued: ${job.id}`);
import os
import requests

response = requests.post(
    "https://api.tscaps.io/v1/automation-jobs",
    headers={"Authorization": f"Bearer {os.environ['TSCAPS_API_KEY']}"},
    json={
        "videoUrl": "https://example.com/reel.mp4",
        "templateId": "mira",
    },
)

job = response.json()
print(f"Job queued: {job['id']}")

The API responds immediately with 202 Accepted and a job object:

{
  "id": "9f2c48e1-5b7a-4a29-8874-9dfc8227b610",
  "status": "queued",
  "phase": "queued",
  "templateId": "mira",
  "quotedSeconds": null,
  "format": "mp4",
  "quality": "high",
  "resolution": null,
  "percent": null,
  "downloadUrl": null,
  "outputExpiresAt": null,
  "failureReason": null,
  "failureCode": null,
  "settledAt": null,
  "createdAt": "2026-09-12T10:11:38.000Z"
}

Direct file uploads: If your video file is stored locally or behind a private firewall, use our Direct file uploads flow to upload the binary file directly via presigned URLs.

2. Check job status

Video processing is asynchronous. Poll GET /v1/automation-jobs/:id until status resolves to succeeded or failed.

curl https://api.tscaps.io/v1/automation-jobs/9f2c48e1-5b7a-4a29-8874-9dfc8227b610 \
  -H "Authorization: Bearer $TSCAPS_API_KEY"
async function waitForVideo(jobId) {
  while (true) {
    const response = await fetch(`https://api.tscaps.io/v1/automation-jobs/${jobId}`, {
      headers: { Authorization: `Bearer ${process.env.TSCAPS_API_KEY}` },
    });
    const state = await response.json();

    if (state.status === "succeeded") {
      return state.downloadUrl;
    }
    if (state.status === "failed") {
      throw new Error(`Job failed: ${state.failureCode} (${state.failureReason})`);
    }
    if (state.status === "cancelled") {
      throw new Error("Job was cancelled.");
    }

    // Wait 5 seconds before checking again
    await new Promise((resolve) => setTimeout(resolve, 5000));
  }
}

const downloadUrl = await waitForVideo(job.id);
console.log(`Finished video: ${downloadUrl}`);
import os
import time
import requests


def wait_for_video(job_id):
    headers = {"Authorization": f"Bearer {os.environ['TSCAPS_API_KEY']}"}
    while True:
        response = requests.get(
            f"https://api.tscaps.io/v1/automation-jobs/{job_id}",
            headers=headers,
        )
        state = response.json()

        if state["status"] == "succeeded":
            return state["downloadUrl"]
        if state["status"] == "failed":
            raise RuntimeError(f"Job failed: {state['failureCode']} ({state['failureReason']})")
        if state["status"] == "cancelled":
            raise RuntimeError("Job was cancelled.")

        # Wait 5 seconds before checking again
        time.sleep(5)


download_url = wait_for_video(job["id"])
print(f"Finished video: {download_url}")

As the job runs, the phase property progresses through:

  • queued: Waiting for processing capacity.
  • ingesting: Downloading and validating the source video.
  • transcribing: Extracting speech and aligning timestamps.
  • rendering: Drawing caption animations and burning them into the video frames (percent reflects render completion from 0 to 100).
  • succeeded: The output file is rendered, uploaded, and ready to download.

Real-time webhook notifications

Instead of polling, configure a webhookUrl to receive an instant callback as soon as the job finishes. Learn more in the Webhooks guide.

3. Download the result

When status reaches succeeded, the response includes downloadUrl, a secure presigned URL pointing directly to the final rendered video, and outputExpiresAt indicating when the link expires (stored for 7 days).

{
  "id": "9f2c48e1-5b7a-4a29-8874-9dfc8227b610",
  "status": "succeeded",
  "phase": "succeeded",
  "templateId": "mira",
  "quotedSeconds": 48,
  "format": "mp4",
  "quality": "high",
  "resolution": { "width": 1080, "height": 1920 },
  "percent": null,
  "downloadUrl": "https://storage.tscaps.io/outputs/9f2c48e1-...?token=...",
  "outputExpiresAt": "2026-09-19T10:14:00.000Z",
  "failureReason": null,
  "failureCode": null,
  "settledAt": "2026-09-12T10:12:26.000Z",
  "createdAt": "2026-09-12T10:11:38.000Z"
}

Next steps

  • API reference: Inspect every endpoint, request parameter, frame budget rule, and failure code.
  • Direct file uploads: Learn how to upload private video files without a public URL.
  • Webhooks: Receive asynchronous delivery notifications and verify signatures.
  • Limits & quotas: Review duration, resolution, concurrency, and rate limits per plan.