ScriptHaul API
Log inGet API key

OpenAPI reference

Explore the request fields, responses, and examples for every endpoint. Download the OpenAPI JSON.

Select Authorize and paste your API key into the Bearer field. Requests run against this API host and use your account's normal credits and limits. Your key stays in this page's memory until you close or reload it.

The interactive reference loads when JavaScript is enabled. The endpoint list below is always available.

Read the endpoint list
POST/v1/auth/code — Send a six-digit verification code

operationId: requestAuthCode

POST/v1/auth/logout — End the dashboard session

operationId: logoutSession

Deletes the session behind the sh_dashboard cookie and clears the cookie. Like every cookie-authenticated mutation it requires the X-ScriptHaul-Dashboard: 1 header. API keys have no session to end.

POST/v1/auth/verify — Verify a code and return a session and first key

operationId: verifyAuthCode

GET/v1/keys — List account keys without secret values

operationId: listKeys

POST/v1/keys — Create and show a key once

operationId: createKey

POST/v1/keys/{keyId} — Rename a key or set its daily credit cap

operationId: updateKey

DELETE/v1/keys/{keyId} — Revoke immediately or with a 24-hour grace period

operationId: revokeKey

POST/v1/keys/{keyId}/rotate — Create a replacement and give the old key 24 hours of grace

operationId: rotateKey

GET/v1/transcript — Get one cache-first transcript

operationId: getTranscript

Use exactly one query mode: video_id starts or reads a transcript; request_id polls an earlier 202 response. The two parameters are mutually exclusive. A cache hit costs 0 credits and a cold delivery 1. With translate=true, when YouTube declines to translate the captions, the transcript is delivered in the requested language for 300 credits per started 10,000 characters of transcript (at most 1,500), on top of the delivery credit, labelled translation: served; nothing extra is charged when it cannot be delivered.

GET/v1/video — Get already-known video and cache facts without an upstream fetch

operationId: getVideoFacts

Returns only facts ScriptHaul already holds; it never triggers a transcript fetch or a YouTube Data API call. Identify the video with exactly one of video_id, input, or url.

GET/v1/videos — List up to 500 channel, playlist, or resolved-list videos

operationId: listVideos

Lists a channel or playlist snapshot, or a resolved list: key. Identify the source with exactly one of url or input.

POST/v1/videos/resolve — Extract and validate up to 500 video links from text

operationId: resolveVideos

GET/v1/account — Get account summary or connected assistant apps

operationId: getAccount

Without resource, return account buckets, limits, keys, purchases, and webhook settings. resource=connected_apps lists unrevoked OAuth grants with client name, created and last-used dates, and scope mcp; this mode requires a dashboard session and returns no API keys or OAuth tokens. Grants and metering identities are created at successful code exchange, not consent. At most ten grants remain unrevoked; a new completed connection atomically revokes the oldest by creation date. Last-used dates are written at most once per five minutes. All grants for an account share one tier allowance pool for request rate, cold-fetch/search concurrency, and daily counters, including revoked grants’ daily usage. Ordinary API keys retain their independent per-key limits; free search replay remains grant-specific. Refresh expiry is fixed at 30 days after initial exchange, not renewed by refresh. Client registrations also expire after 30 days and can require an earlier reconnection. See /docs/authentication#oauth-for-assistants. Expired connections remain listed until revoked or replaced.

PUT/v1/account — Dashboard alias: create or replace the account webhook with the session cookie

operationId: putAccountResource

Same behaviour as PUT /v1/webhooks, reachable with the dashboard session cookie plus the X-ScriptHaul-Dashboard: 1 header. The resource parameter selects the operation; the only value today is webhook.

DELETE/v1/account — Delete a webhook, close the account, or revoke a connected app

operationId: deleteAccountResource

Dashboard mutations require the session cookie and X-ScriptHaul-Dashboard: 1. resource=connected_apps&id=<grant_id> revokes an OAuth grant and requires a dashboard session. Refresh-token revocation and local authentication-cache invalidation are immediate; another isolate can accept an already memoized access token for up to 30 seconds, never beyond its expiry. It cannot be called with an API key or an OAuth token. Other resource modes retain their existing authentication rules.

GET/v1/usage — Get account or owned-key daily rollups

operationId: getUsage

Without resource, daily usage rollups for the account or one owned key. With resource=ledger, the append-only credit ledger (newest first) paged with limit and offset; the CSV format applies to rollups only.

POST/v1/checkout — Create a one-time Stripe Checkout Session or request an untouched-block refund

operationId: createCheckoutOrRefund

POST/v1/billing/stripe — Receive signed Stripe events

operationId: stripeWebhook

GET/v1/billing/portal — Get a Stripe customer portal URL

operationId: getBillingPortal

GET/v1/webhooks — Get the account webhook configuration without its signing secret

operationId: getWebhook

PUT/v1/webhooks — Create or replace the account webhook, optionally rotating its signing secret

operationId: putWebhook

The signing secret is returned once: when the webhook is first configured and whenever rotate_secret is true. Rotation does not re-sign deliveries already enqueued; they keep the secret snapshot they were created with.

DELETE/v1/webhooks — Delete the account webhook configuration

operationId: deleteWebhook

GET/v1/jobs — List account-owned API jobs

operationId: listJobs

Returns account-owned API and monitor-created jobs. A monitor-created job includes optional monitor_id identifying its account watch; clients should label it from that field. It remains visible after changes to the credential that created the monitor.

POST/v1/jobs — Create an idempotent bulk transcript job of up to 500 videos

operationId: createJob

With translate=true, each video whose captions YouTube declines to translate is delivered in the job's language for 300 credits per started 10,000 characters of transcript (at most 1,500), on top of the delivery credit, labelled translation: served; nothing extra is charged when it cannot be delivered. That price is never part of the job's reservation. An Idempotency-Key replay keeps the stored choice.

GET/v1/jobs/{jobId} — Get job progress, exact credits, webhook delivery state, and video rows

operationId: getJob

A monitor-created job includes optional monitor_id identifying its account watch; ordinary API jobs omit it. Monitor-created jobs use account daily caps and remain account-owned after creator-key changes or OAuth disconnection. Ordinary API-key requests retain their per-key limits and may continue when monitor admission reaches its account cap. A job created with translate=true includes translate: true and translation_credits, the credits charged for its translated videos, beside credits; each of its video rows carries translation_credits. Other jobs omit those additions.

GET/v1/jobs/{jobId}/videos — Page and filter per-video outcomes

operationId: listJobVideos

GET/v1/jobs/{jobId}/manifest — Download a complete JSON or CSV job manifest

operationId: getJobManifest

For a monitor-created job, the JSON job object and each video record include monitor_id, and the CSV has a monitor_id column. For a job created with translate=true, each video record includes translation_credits, and the CSV ends with a translation_credits column. Ordinary API jobs omit those additions. Archive manifests use the same identification.

GET/v1/jobs/{jobId}/archive — Queue or download a zero-credit server-side ZIP archive

operationId: getJobArchive

Available only to a Bearer API key after the owned job is terminal. With no format parameter, the job's single format is used. Multi-format requests are split into ZIP parts before any part can exceed 80 MiB; the index response identifies numbered parts. Archives expire after seven days.

GET/v1/jobs/{jobId}/files/{videoId} — Download one completed transcript in a supported format

operationId: getJobFile

GET/v1/jobs/{jobId}/events — Read a reconnectable SSE progress snapshot

operationId: getJobEvents

POST/v1/jobs/{jobId}/retry — Reserve and retry eligible zero-cost transient failures

operationId: retryJob

POST/v1/jobs/{jobId}/cancel — Cancel queued work and release every unsettled reservation once

operationId: cancelJob

GET/v1/status — Get public service and per-strategy health

operationId: getStatus

GET/v1/search — Search YouTube or within one channel

operationId: searchYouTube

One credit per delivered page, including an empty page; zero on failure. An identical q, type, channel, and continuation retried with the same key within 60 seconds returns the same page for zero credits and consumes no additional daily page allowance. Other pages are not cached. Search has its own per-key daily allowance of 50 pages for free keys and 2,000 for paid keys, independent of cold transcript fetch counters; the approximate per-key rpm limit and daily credit cap also apply. Search never uses the YouTube Data API search.list endpoint. Resolving a channel handle is free and cached. Send opaque continuations unchanged with the same other parameters. A second daily allowance admits at most 150 attempts per free key or 6,000 per paid key (three times the page cap). Admitted attempts count before upstream work even if they later fail, but failures cost zero credits. Denied admission, in-flight duplicates and successful same-key replays add no attempt or page allowance. An in-flight identical request returns retryable 429 search_in_progress with Retry-After: 1; repeat the same key and parameters after waiting, and once delivery succeeds its page can be replayed free. A failed first request has no delivered page to replay. Malformed individual results are dropped while valid rows remain. Recommendation shelves such as Latest from and People also watched, including their nested results and continuation tokens, are excluded from organic results.

GET/v1/channels/resolve — Resolve a public channel to its stable IDs

operationId: resolveChannel

Free channel resolution with cached results. Accepts a handle, a UC ID, or a YouTube /channel/, /user/, or /c/ URL. Legacy /c/ names are resolved as handles. Allows 100 requests per free key per UTC day or 1,000 per paid key. Valid admitted requests count even on warm results, including negative-cache hits. A definitive missing channel returns 404 InvalidInput and is cached for 24 hours across keys by normalized input; repeats use no additional Data API units during that interval. Transient upstream, configuration, and quota failures are not cached as missing channels. The allowance is checked before upstream work; exhaustion returns 429 QuotaExceeded with Retry-After until 00:00 UTC. The normal key request rate also applies, and cold resolution obeys the existing Data API capacity guard. Use the returned channel_id for latest uploads and uploads_playlist_id for full enumeration.

GET/v1/channels/latest — Get the newest channel or playlist RSS entries

operationId: getLatestVideos

Zero credits. Supply exactly one channel or playlist. Reads only YouTube public RSS, with a ten-minute cache and at most the newest fifteen entries. Allows 500 requests per free key per UTC day or 5,000 per paid key, including valid feed-cache hits. The allowance is checked before upstream work; exhaustion returns 429 QuotaExceeded with Retry-After until 00:00 UTC. The normal key request rate also applies. A UC ID or a channel URL containing that ID works directly; a handle must already be known from channel resolution. Unknown aliases return 400 channel_resolution_required with resolve_url. Latest uploads never calls a relay or the YouTube Data API and never fetches transcripts. This limited feed is not full channel or playlist enumeration. YouTube returned 404 for a well-formed channel or playlist RSS feed ID. Returns nonretryable NotFound with code feed_not_found; check the ID before retrying. Costs zero credits.

GET/v1/library — Check transcript coverage for a channel or playlist

operationId: getLibraryCoverage

Authenticated source-caption coverage for exactly one channel or playlist. Costs 0 credits. Allows 200 requests per free key per UTC day or 2,000 per paid key, including valid warm snapshots. The allowance is checked before upstream work; exhaustion returns 429 QuotaExceeded with Retry-After until 00:00 UTC. The normal key request rate also applies. A cold first enumeration page consumes the separate normal enumeration allowance and Data API capacity; further contiguous warm pages extend the snapshot without additional cold enumeration. Missing IDs and the create_job cold selection are capped at 500. snapshot_complete is false while source enumeration is truncated; next_offset identifies the next enumeration page. Display metadata is refreshed only when the original listing snapshot changes; repeated warm calls do not rewrite unchanged fields or extend their original 30-day freshness deadline. Indexing preserves newer listing metadata. Required counts.uncaptioned counts known non-indexed videos recorded as no_captions or unavailable; they are excluded from missing and cold selections. An existing searchable index takes precedence. complete is true only for a complete source snapshot with nothing indexable missing, and may be true while counts.uncaptioned is positive. This does not promise captions for every known video.

GET/v1/library/search — Search indexed transcript passages in exactly one channel or video

operationId: searchLibrary

Zero-credit BM25-ranked source-caption passages with timestamp watch URLs. Requires a Bearer API key and exactly one channel or video_id; the scope is applied during the index search. Channel membership requires confirmed public-listing provenance. A URL-only fetched video stays searchable by video_id until a listing confirms its channel; player metadata alone does not establish membership. ID-only membership records prior listing, not current public visibility, and survives the original 30-day expiry of titles and publication dates. No site-wide or cross-channel search. Queries support words, quoted phrases, and prefix terms only, up to 500 characters and 32 terms/phrases. Prefixes require at least three characters in the final word, including quoted phrase prefixes; shorter prefixes return 400 InvalidInput. Free allowance: 500 searches/key/UTC day; paid: 20,000. Repeated valid searches count. The daily allowance is enforced before upstream work; exhaustion returns 429 QuotaExceeded with Retry-After until 00:00 UTC. Normal key RPM also applies. Translation output is not indexed; coverage can lag cache delivery. Channel coverage is read from stored channel totals, without scanning the full video list or processing pending enumeration during search. API listing pages, RSS reads, indexing, coverage refreshes, and bounded background synchronization maintain the counters. Listings captured only through the free site can lag until synchronization.

GET/v1/monitors — List account-owned channel and playlist monitors

operationId: listMonitors

Zero credits. Returns up to 1,000 account-owned active, paused, and cancelled monitors, newest first. API keys and permitted dashboard sessions can read their own account. Monitors belong to the account and keep running after creator-key rotation, deletion, revocation, or OAuth disconnection. Automatic jobs use account daily caps, including existing key usage, rather than the creating credential's allowances. Job lists, reads, manifests, and completion events identify this work with monitor_id. Pause reasons are exactly insufficient_credits (resumes after a purchase restores enough available credits), webhook_missing (the relied-on account webhook was deleted; resumes after configuring one), and feed_unavailable (six consecutive failed feed checks; retried daily and resumed on success). Overlapping causes prioritize webhook absence, feed failure, then credits; clearing one does not bypass another. Ordinary API-key requests retain their per-key limits and may continue when monitor admission reaches its account cap.

POST/v1/monitors — Watch future channel or playlist RSS uploads

operationId: createMonitor

Requires an API key. Creation costs zero credits. A new monitor baselines current RSS entries without historical fetches and returns 201 with idempotent:false. An account-scoped Idempotency-Key replay returns the original monitor unchanged with 200 and idempotent:true, even with changed payload fields or after cancellation; replay happens before source resolution or upstream work. An active or paused watch for the same account/channel or account/playlist also returns unchanged with 200 and idempotent:true. A new key on that source becomes an alias for the existing watch; aliases persist until the monitor/account record is deleted. Use a fresh key for a replacement after cancellation. Non-ID channel inputs use channel resolution, including its separate daily allowance and 24-hour negative cache; direct UC and playlist IDs need no resolution. Defaults: auto_fetch=false, language=en, fallback=true. One monitor per free account; 25 per paid account. Checks run at most once per 15 minutes and use a ten-minute RSS cache without proxy or Data API calls. auto_fetch creates ordinary one-video jobs; one credit is charged per successful cold transcript, zero for cache hits/failures. Monitors belong to the account and keep running after creator-key rotation, deletion, revocation, or OAuth disconnection. Automatic jobs use account daily caps, including existing key usage, rather than the creating credential's allowances. Job lists, reads, manifests, and completion events identify this work with monitor_id. Pause reasons are exactly insufficient_credits (resumes after a purchase restores enough available credits), webhook_missing (the relied-on account webhook was deleted; resumes after configuring one), and feed_unavailable (six consecutive failed feed checks; retried daily and resumed on success). Overlapping causes prioritize webhook absence, feed failure, then credits; clearing one does not bypass another. Ordinary API-key requests retain their per-key limits and may continue when monitor admission reaches its account cap. YouTube returned 404 for a well-formed channel or playlist RSS feed ID. Returns nonretryable NotFound with code feed_not_found; check the ID before retrying. Costs zero credits. Scheduled monitor polling and the monitor webhook outbox each drain until empty or their 45-second maximum, sharing a 600-operation ceiling with library backfill and rotating first priority between ten-minute ticks. Remaining work stays eligible for a later run; this is not a delivery-time guarantee.

GET/v1/monitors/{monitorId} — Inspect an account-owned monitor

operationId: getMonitor

Zero credits. Inspect the account-owned watch, including last_error and consecutive_failures. Monitors belong to the account and keep running after creator-key rotation, deletion, revocation, or OAuth disconnection. Automatic jobs use account daily caps, including existing key usage, rather than the creating credential's allowances. Job lists, reads, manifests, and completion events identify this work with monitor_id. Pause reasons are exactly insufficient_credits (resumes after a purchase restores enough available credits), webhook_missing (the relied-on account webhook was deleted; resumes after configuring one), and feed_unavailable (six consecutive failed feed checks; retried daily and resumed on success). Overlapping causes prioritize webhook absence, feed failure, then credits; clearing one does not bypass another. Ordinary API-key requests retain their per-key limits and may continue when monitor admission reaches its account cap.

DELETE/v1/monitors/{monitorId} — Cancel future monitor checks and automatic job creation

operationId: cancelMonitor

Zero credits. Existing transcript jobs continue; cancel those jobs separately. API keys and permitted dashboard sessions can cancel only their own monitors.