API Reference

One key, eight endpoints, one currency. Every response is JSON, every request is a plain HTTP call — no SDK, no OAuth dance, no quota units to budget.

Introduction

The base URL is https://api.transcriptapi.io. All endpoints are served over HTTPS; plain HTTP is redirected. Requests need no body unless the reference says otherwise, and parameters go in the query string.

quickstart
# every call looks like this
curl "https://api.transcriptapi.io/transcript?video_id=dQw4w9WgXcQ" \
  -H "Authorization: Bearer $API_KEY"

Authentication

Pass your API key as a bearer token on every request. Keys are created on first sign-in and shown in your dashboard.

header
Authorization: Bearer ta_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

A missing, malformed, or unknown key returns 401. Keys carry no scopes — one key reaches every endpoint on this page.

Keep it server-side

Your key is your balance. Calling the API straight from a browser or mobile app exposes it to anyone who opens devtools. Proxy through your own backend instead.

Credits

One credit is one billable call. New accounts start with 20 free credits, no card required.

  • Every endpoint below costs 1 credit, except where noted.
  • Translation adds 1 credit per 40 transcript segments, minimum 2 — a long video genuinely costs more to translate, so it is priced that way rather than as a flat fee.
  • Cache hits are free. A repeated request served from cache never touches your balance.
  • Failures are refunded. If a request is charged and then fails, the credits are returned automatically and the response says so.

The exact cost of a call is recorded per request, so your dashboard total always reconciles against what you were actually served.

Errors

Errors use standard status codes and always carry a detail string.

StatusMeaningCredits
401Missing or invalid API keyNot charged
402Insufficient credits for this callNot charged
422A parameter is missing or out of rangeNot charged
502YouTube could not be reached or returned something unusableRefunded
502 response
{
  "detail": "Upstream request failed: IpBlocked. Your credits have been refunded."
}

Caching & limits

Responses are cached server-side and served free of charge on a repeat request. Transcripts are cached indefinitely — a transcript does not change once published. Search and channel search are cached for one hour, channel listings and playlists for six.

There is no enforced request-rate limit today. Please stay reasonable; one will be introduced before it becomes a problem, and it will be documented here first.

GET/transcript1 credit · +1 / 40 segments to translate

Returns the full timed transcript of a public video. Works with both auto-generated and manually uploaded captions.

ParameterTypeDefaultDescription
video_id requiredstringThe YouTube video ID — the v= part of a watch URL.
language optionalstringenPreferred caption language code. Falls back to English, then to whatever the video actually has.
translate_to optionalstringTranslate the transcript into this language using AI. Accepts a code or a name, e.g. de or German.
request
curl "https://api.transcriptapi.io/transcript?video_id=dQw4w9WgXcQ&translate_to=de" \
  -H "Authorization: Bearer $API_KEY"
200 response
{
  "video_id": "dQw4w9WgXcQ",
  "translated_to": "de",
  "transcript": [
    {
      "start": 0.0,
      "duration": 3.52,
      "text": "Wir kennen uns beide gut aus"
    }
  ]
}

start and duration are seconds from the beginning of the video, rounded to two decimals. Segments are returned in playback order.

Search all of YouTube and get structured results back.

ParameterTypeDefaultDescription
q requiredstringThe search query.
limit optionalinteger20How many results to return, 1–50.
200 response
{
  "query": "fastapi tutorial",
  "results": [
    {
      "id": "0sOvCWFmrtA",
      "title": "FastAPI - A python framework",
      "channel": "Amigoscode",
      "views": "412K views",
      "duration": "27:38"
    }
  ]
}
GET/channel/videos1 credit

List a channel's uploads, newest first. Accepts a channel ID, a handle, or a custom URL slug.

ParameterTypeDefaultDescription
channel_id requiredstringChannel ID (UC…), @handle, or custom URL name.
limit optionalinteger50How many videos to return, 1–200.
200 response
{
  "channel_id": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
  "title": "Google for Developers",
  "total": 50,
  "videos": [
    {
      "id": "kN_iMEAi1dw",
      "title": "Build a live translation broadcast app",
      "views": "236 views",
      "duration": "12:37",
      "published": "1 hour ago"
    }
  ]
}

Search within one channel's uploads.

ParameterTypeDefaultDescription
channel_id requiredstringChannel ID, @handle, or custom URL name.
q requiredstringQuery matched against video titles.
limit optionalinteger20How many results to return, 1–50.
200 response
{
  "channel_id": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
  "query": "gemini",
  "results": [
    {
      "id": "kacf2bib-X0",
      "title": "Hands on with Gemini 3.7 Flash",
      "channel": "Google for Developers",
      "views": "2.7K views",
      "duration": "4:21"
    }
  ]
}
GET/playlist1 credit

Read every video in a public playlist, in playlist order.

ParameterTypeDefaultDescription
playlist_id requiredstringThe playlist ID — the list= part of a playlist URL.
limit optionalinteger100How many videos to return, 1–500.
200 response
{
  "playlist_id": "PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab",
  "total": 16,
  "videos": [
    {
      "id": "fNk_zzaMoSs",
      "title": "Vectors | Chapter 1, Essence of linear algebra",
      "views": "12M views",
      "duration": "9:52",
      "published": "10 years ago"
    }
  ]
}
POST/channel/subscribefree

Get a POST to your own URL when a channel publishes something new, instead of polling for it yourself. Send a JSON body.

ParameterTypeDefaultDescription
channel_id requiredstringThe channel to watch.
webhook_url requiredurlWhere the notification is delivered. Must be a valid absolute URL.
request
curl -X POST "https://api.transcriptapi.io/channel/subscribe" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"channel_id":"UC_x5XG1OV2P6uZZ5FSM9Ttw","webhook_url":"https://you.example/hook"}'

Subscribing again for the same channel replaces the existing hook rather than creating a second one.

DELETE/channel/subscribefree

Stop notifications for a channel.

ParameterTypeDefaultDescription
channel_id requiredstringThe channel to stop watching. Passed in the query string.
request
curl -X DELETE "https://api.transcriptapi.io/channel/subscribe?channel_id=UC_x5XG1OV2P6uZZ5FSM9Ttw" \
  -H "Authorization: Bearer $API_KEY"

Webhook payload

Subscribed channels are checked every 15 minutes. When a new upload appears, we POST this to your URL:

POST https://you.example/hook
{
  "channel_id": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
  "video_id": "kN_iMEAi1dw"
}
Delivery is best-effort

There is no retry and no signature yet. Treat the payload as a nudge to go fetch the video, not as trusted input, and do not rely on it for anything you cannot reconcile by polling. The first check after subscribing only records the current latest video — you are notified from the next upload onwards.

GET/healthfree · no auth

Liveness check. Needs no API key and never costs a credit.

200 response
{ "status": "ok" }