ScriptHaul API
Log inGet API key

Migrating from transcriptapi.com

ScriptHaul uses Bearer authentication, explicit language results, free cache hits, and pay-as-you-go credit blocks.

Existing conceptScriptHaul
API key query parameterAuthorization: Bearer sh_live_…
YouTube URL parameterExtract its 11-character YouTube ID and send it as video_id
Plain transcriptformat=clean
Timestamped transcriptformat=timestamped
JSON transcriptformat=json
Translation languagelanguage=xx; inspect requested/delivered/translation
Silent language fallbackfallback=true, always labelled
Strict languagefallback=false; refusal is retryable and costs 0
One credit for every call1 for a successful cold transcript delivery or a delivered search page; transcript cache hits and failures cost 0
Subscription/top-up balanceOne-time blocks; purchased credits never expire
Client-side channel loopOne durable bulk job with manifests, per-file downloads, events, and a signed webhook

Discovery endpoint map

transcriptapi.com endpointScriptHaul endpointCredits
/youtube/searchGET /v1/search?q=…&type=video1 per delivered page
/youtube/channel/searchGET /v1/search?q=…&channel=@handle1 per delivered page
/youtube/channel/videosGET /v1/videos?url=https://www.youtube.com/@handle0; cold enumeration limits apply
/youtube/channel/latestGET /v1/channels/latest?channel=UC…0
/youtube/channel/resolveGET /v1/channels/resolve?input=@handle0
/youtube/playlist/videosGET /v1/videos?url=https://www.youtube.com/playlist?list=PL…0; cold enumeration limits apply

Encode nested URLs as query values. Search uses opaque continuation tokens; channel and playlist listing uses offsets in multiples of 500. Repeating an identical search page with the same key within 60 seconds costs zero. Latest uploads return the RSS feed's newest 15 entries with a ten-minute cache; use full listing for older videos.

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

Do not mechanically copy a key from a query string into a new URL. Move it into the header first, then verify your retry policy against typed errorClass and retryable fields.

Equivalent request in four languages

Each version uses an Authorization header, strict English, and JSON output. Maintained runnable variants 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=json" \
  --data-urlencode "language=en" --data-urlencode "fallback=false"
import os, urllib.request
url = "https://api.scripthaul.com/v1/transcript?video_id=jNQXAC9IVRw&format=json&language=en&fallback=false"
request = urllib.request.Request(url, headers={"Authorization": f"Bearer {os.environ['SCRIPTHAUL_API_KEY']}"})
print(urllib.request.urlopen(request).read().decode())
const url = "https://api.scripthaul.com/v1/transcript?video_id=jNQXAC9IVRw&format=json&language=en&fallback=false";
const response = await fetch(url, { headers: { Authorization: `Bearer ${process.env.SCRIPTHAUL_API_KEY}` } });
console.log(await response.json());
url := "https://api.scripthaul.com/v1/transcript?video_id=jNQXAC9IVRw&format=json&language=en&fallback=false"
req, _ := http.NewRequest("GET", url, 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)