ScriptHaul API
Log inGet API key

Quickstart

Get a key with an email address, then make one authenticated request. No password is required.

1. Get a key

Sign up on api.scripthaul.com: enter your email, type the six-digit code from the message, accept the terms, and copy the sh_live_… key shown once. Sign-up runs in the browser behind a bot check, so there is no scripted step for it; more keys, rotation and revocation live on the dashboard and /v1/keys.

Store the key in a secret manager. Never put it in a URL, log, browser bundle, or query string.

export SCRIPTHAUL_API_KEY="sh_live_replace_me"

2. Fetch a transcript

curl --get https://api.scripthaul.com/v1/transcript \
  -H "Authorization: Bearer $SCRIPTHAUL_API_KEY" \
  --data-urlencode "video_id=jNQXAC9IVRw" \
  --data-urlencode "format=clean"

Inspect X-Cache, X-Credits-Charged, X-Credits-Balance, and X-Request-Id. A cache hit costs 0. A successful cold delivery costs 1. Failures cost 0.

3. Download SRT

curl --get https://api.scripthaul.com/v1/transcript \
  -H "Authorization: Bearer $SCRIPTHAUL_API_KEY" \
  --data-urlencode "video_id=jNQXAC9IVRw" \
  --data-urlencode "format=srt" \
  --data-urlencode "raw=1" \
  -o jNQXAC9IVRw.srt

Cold calls may return 202 after 25 seconds. Follow the returned poll_url with the same Bearer key; polling itself does not add another delivery charge.

Thin clients

The MIT-licensed JavaScript and Python clients are published to npm and PyPI once the live verification run passes; until then use curl or copy the examples. Every response carries meta (cache, credits charged, balance, rate limit, request id, and library coverage), and wait() stops on a paused job instead of polling through it. Both clients expose transcripts, discovery, channel resolution and latest uploads, library coverage and search, monitors, and durable jobs. They bound retries for 429/502/503 responses and 202 polling, raise typed errors that mirror errorClass, and keep request_id on exceptions.

import ScriptHaul from "scripthaul";
const client = new ScriptHaul({ apiKey: process.env.SCRIPTHAUL_API_KEY });
const job = await client.jobs.create({ input: "https://www.youtube.com/@example" });
await job.wait();
from scripthaul import ScriptHaul
client = ScriptHaul()
job = client.jobs.create(input="https://www.youtube.com/@example").wait()

Choose a workflow

GoalStart hereCost
Find videos by topic or inside one channelYouTube search1 credit per delivered page; identical per-key retry within 60 seconds is free
Resolve a creator or inspect recent uploadsChannels and latest uploads0 credits
Inspect a full source or a pasted selectionListing, pasted lists0 credits; cold enumeration has its own allowance
Read one video in a chosen format or languageTranscripts, video facts1 credit per successful cold transcript; cache hits and failures are free
Export a channel, playlist, or selectionBulk jobs, webhooksJobs reserve the cold count; files, manifests, and archives cost 0 credits
Answer what a channel said, with timestamp citationsTranscript libraryCoverage and scoped searches cost 0 credits; fill missing captions through ordinary jobs
Keep new captions arriving automaticallyMonitorsMonitoring costs 0 credits; optional automatic jobs use normal transcript credits
Connect an assistant or automationMCP client setup, agent skill, examples and n8nConnection costs 0 credits; tools use their documented operation costs

Use the interactive API reference to inspect every request and response schema and make same-origin requests with your Bearer key. The page also keeps a readable reference when JavaScript is disabled. OpenAPI JSON, llms.txt, and the full agent reference describe the same API.

For a library question, check coverage first, explain the cold count, fetch missing captions when authorized, then search passages and cite their timestamp URLs. Library search always requires one channel or one video scope. Use credits and limits to budget the work and typed errors to choose the right retry or next step.

Quickstart in four languages

All examples read the key from SCRIPTHAUL_API_KEY. Maintained runnable versions are in the examples directory.

curl --get https://api.scripthaul.com/v1/transcript \
  -H "Authorization: Bearer $SCRIPTHAUL_API_KEY" \
  --data-urlencode "video_id=jNQXAC9IVRw" --data-urlencode "format=clean"
import os, urllib.request
request = urllib.request.Request("https://api.scripthaul.com/v1/transcript?video_id=jNQXAC9IVRw&format=clean")
request.add_header("Authorization", f"Bearer {os.environ['SCRIPTHAUL_API_KEY']}")
print(urllib.request.urlopen(request).read().decode())
const response = await fetch("https://api.scripthaul.com/v1/transcript?video_id=jNQXAC9IVRw&format=clean", {
  headers: { Authorization: `Bearer ${process.env.SCRIPTHAUL_API_KEY}` },
});
console.log(await response.json());
req, _ := http.NewRequest("GET", "https://api.scripthaul.com/v1/transcript?video_id=jNQXAC9IVRw&format=clean", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("SCRIPTHAUL_API_KEY"))
response, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer response.Body.Close()
io.Copy(os.Stdout, response.Body)