Changelog
Contract changes are listed by date. Subscribe to the RSS feed to follow them.
2026-10-03 — Bulk jobs in the language you asked for
POST /v1/jobsand keyed MCPcreate_bulk_jobgain an opt-intranslatefield, false by default; any other value is a400withcode: "invalid_translate". On a job that sets it, each video whose captions YouTube declines to translate is delivered in the job's language whenever ScriptHaul can, for 300 credits per started 10,000 characters of transcript (at most 1,500), on top of the delivery credit. The row is labelled like any served translation, and a strict job's video receives it instead of a retryable refusal.- Without
translate, every job is unchanged. With it, nothing extra is charged for a video whose requested language cannot be delivered, and the price is never part of the job's reservation: each translated video pays it from the available balance when delivered, within the key's daily credit cap. - A job created with
translate: trueshowstranslate: trueand atranslation_creditstotal besidecredits, and its video rows, manifests (a trailing column) and terminal webhook carrytranslation_credits. The credit ledger labels each chargeTranslation.
2026-10-02 — Transcripts in the language you asked for
GET /v1/transcriptgains an opt-intranslateparameter, and keyed MCPget_transcriptatranslateargument, both false by default. With it, when YouTube declines to translate a video's captions, the transcript is delivered in the requested language whenever ScriptHaul can, for 300 credits per started 10,000 characters of transcript (at most 1,500), on top of the delivery credit. The response is labelled like any served translation:deliveredmatchesrequestedandtranslationisserved. A strict request receives it instead oftranslation_refused.- Without
translate, every response is unchanged. With it, nothing extra is charged when the requested language cannot be delivered: the labelled source track and the existing refusal codes apply. Later requests for the same video and language are cache hits at 0 credits. - The credit ledger labels the charge
Translation, and customer-set per-key daily credit caps count it, including while it is still in progress.
2026-09-11 — Refreshing cached transcripts
GET /v1/transcript?fresh=truerefetches a video from YouTube and replaces the cached copy, as a cold delivery for one credit. Use it when a creator edited their captions.- Auto-generated caption entries older than 30 days are re-checked once, in the background, on the next cache hit, at no charge, so a manual track the creator added later is picked up on its own.
2026-09-07 — Ledger paging by cursor
GET /v1/usage?resource=ledgerreturnspagination.next_cursor; pass it back ascursorto walk the whole ledger with no ceiling, newest first, unaffected by rows that arrive meanwhile.sinceanduntilbound a page to a date range.offsetstill works and remains capped at 100,000.- The dashboard's credit ledger shows the newest 100 entries and a "Show older entries" button; Export CSV walks the full history by cursor.
- A repeat purchase is never gated. The earlier rule that refused a second block until 100 credits were consumed is gone.
2026-09-06 — Discovery, connection, and transcript library
- YouTube-wide and in-channel search costs one credit per delivered page. Identical per-key page retries within 60 seconds cost zero. Channel resolution and RSS latest uploads cost zero credits.
- Account MCP supports OAuth alongside API keys, with revocable Connected apps in the dashboard. Eight client setup guides and the installable agent skill cover account and keyless connections.
- Library coverage reports indexed videos, missing IDs, and the cold count. Scoped phrase and prefix searches return source-caption passages with timestamp citations at zero credits; the daily allowance is 500 searches per free key or 20,000 per paid key.
- Channel and playlist monitors watch recent RSS entries at zero credits. Optional automatic fetching uses ordinary transcript jobs, including reservations, delivery charges, insufficient-credit pauses, and signed events. Dashboard controls show checks, new-video counts, and cancellation.
- The keyed MCP server exposes twelve tools, including discovery, library search, and monitors. Both SDKs and the 22-scenario curl, Node, Python, and Go example sets cover the expanded API.
- The landing page maps every API route and MCP tool to its docs and costs, with example assistant prompts and dated competitor sources. Pricing states the search-page charge and the zero-credit operations.
- The self-hosted interactive OpenAPI reference accepts a Bearer key for same-origin requests, keeps a readable no-script reference, and loads no third-party scripts. The docs index, OpenAPI, error reference, agent skill, and LLM discovery files are regenerated together.
2026-09-05 — Method handling, sitemap, and examples
- Requests with a known path but an unsupported method now answer
405with anAllowheader and the standard error envelope (method_not_allowed);OPTIONSon a known path answers204. Unknown paths still answer404. docs_urlon errors links to theerrorClasssection of the errors page, which now lists everycodethe class can carry.- Every response carries
X-Request-Id; API responses default toCache-Control: no-store. GET /v1/usage?resource=ledgerand the dashboard aliasesPUT/DELETE /v1/account?resource=webhookare documented in OpenAPI. Unknownresourceoractionvalues answer400.- A Bearer-authenticated client is never refused as a crawler, whatever its User-Agent.
GET /v1/jobs/{id}/archiveanswers409(archive_failed) instead of a200body when a build has exhausted its attempts.- Runnable curl, Node, Python, Go, and n8n examples are published at
/docs/examples. /.well-known/api-catalogis an RFC 9727 Linkset served asapplication/linkset+json.
2026-09-04 — v1 surface
- Passwordless accounts, hashed Bearer keys with rotation and grace-period revocation, and dashboard sessions.
GET /v1/transcriptin seven formats with explicit requested, delivered, fallback, and translation fields;raw=1attachments;202polling for long cold fetches.GET /v1/videofacts,GET /v1/videoschannel and playlist listing with cached flags and cold counts, andPOST /v1/videos/resolvefor pasted lists.- Bulk jobs for up to 500 videos with exact reservation, settlement, pause, resume, retry, and cancel; manifests, per-file downloads, SSE progress, and queued ZIP archives with 80 MiB parts and seven-day expiry.
- Signed webhooks with bounded retries, per-job endpoint overrides, and delivery state on the job.
- Credits, free and paid limits, one-time Stripe credit blocks, self-service refunds, and automatic outage credits.
Smoke-test the current surface
The public status response is the safest post-upgrade smoke test. Maintained runnable variants are in the examples directory.
curl https://api.scripthaul.com/v1/status
import json, urllib.request
with urllib.request.urlopen("https://api.scripthaul.com/v1/status") as response:
status = json.load(response)
print(status["status"], status["canary"])
const response = await fetch("https://api.scripthaul.com/v1/status");
const status = await response.json();
console.log(status.status, status.canary);
response, err := http.Get("https://api.scripthaul.com/v1/status")
if err != nil { log.Fatal(err) }
defer response.Body.Close()
io.Copy(os.Stdout, response.Body)