Back to blog

Migration · TranscriptAPI · YouTube API

Migrating from TranscriptAPI to YTAPI: A Field Guide for Transcript Pipelines

Switching your YouTube transcript pipeline from TranscriptAPI to YTAPI.dev. Covers endpoint mapping, parameter aliases, the language priority list, response field renames, and retry semantics.

· 4 min read · Platform Team

TranscriptAPI and YTAPI.dev share the same core design language — Bearer auth, second-precision segments, credit-based billing — so migration is mostly a matter of renaming things. This guide walks through each difference.

Before you switch, the measured comparison shows how the three APIs behave on uncached videos, and pricing compared works out what each costs at your volume.

1. Authentication: zero changes

Both APIs use Authorization: Bearer <API_KEY>:

# TranscriptAPI
curl -H "Authorization: Bearer YOUR_KEY" "https://transcriptapi.com/api/v2/youtube/transcript?video_url=..."

# YTAPI — identical header
curl -H "Authorization: Bearer YOUR_KEY" "https://api.ytapi.dev/v1/transcripts?video_id=..."

Swap the base URL, keep the header.

2. Endpoint and parameter mapping

TranscriptAPIYTAPINotes
GET /api/v2/youtube/transcriptGET /v1/transcriptsCore transcript endpoint
video_url= (URL, short link, or bare ID)video_id= (alias id=)Bare 11-char IDs work on both; if you pass full URLs, extract the ID
format=json (default)format=segments (default)Same shape: timestamped segments
format=textformat=textIdentical name
include_timestamp=falseformat=textYTAPI's text format is always plain concatenated text
send_metadata=true—See §4: metadata lives on the video info endpoint
language=en,eslanguages=en,es (alias lang)Comma-separated priority list works on both

Minimal migration diff:

# Before (TranscriptAPI)
resp = requests.get(
    "https://transcriptapi.com/api/v2/youtube/transcript",
    headers={"Authorization": f"Bearer {KEY}"},
    params={"video_url": video_id, "format": "json", "language": "en"},
)
data = resp.json()
segments = data["transcript"]

# After (YTAPI)
resp = requests.get(
    "https://api.ytapi.dev/v1/transcripts",
    headers={"Authorization": f"Bearer {KEY}"},
    params={"video_id": video_id, "format": "segments", "languages": "en"},
)
data = resp.json()
segments = data["segments"]

3. Response fields: same units, slight renames

Good news: both APIs use seconds (float) and text / start / duration for segments — no unit conversion needed. The differences are envelope-level:

// TranscriptAPI
{
  "video_id": "dQw4w9WgXcQ",
  "language": "en",              // resolved track code, e.g. "asr-hi"
  "transcript": [{ "text": "...", "start": 0.0, "duration": 4.12 }],
  "length_seconds": 213,
  "lengthText": "3:33"
}

// YTAPI
{
  "video_id": "dQw4w9WgXcQ",
  "language": "en",
  "track_kind": "manual",        // "manual" or "asr"
  "duration_seconds": 213.5,    // note: duration_seconds, not length_seconds
  "has_word_level": false,
  "segments": [{ "text": "...", "start": 0.0, "duration": 4.12 }]
}

Field renames to handle: transcript → segments, length_seconds → duration_seconds (drop lengthText, or format it client-side).

4. Language selection

Both support a comma-separated priority list (language=en,es → languages=en,es). Two subtleties:

  • TranscriptAPI's asr / asr-<code> prefix (e.g. asr-hi = auto-generated Hindi) maps to YTAPI's track_policy: manual_first (default), asr_first, or exact_only. If you were requesting asr-hi explicitly, use languages=hi&track_policy=asr_first.
  • The response's language field on both APIs is the resolved track code. YTAPI additionally returns track_kind (manual/asr) so you don't have to parse prefixes.

5. Metadata and free pre-checks

TranscriptAPI's send_metadata=true returns {title, author_name, author_url, thumbnail_url}, and its /youtube/info endpoint is free. YTAPI's equivalents:

  • GET /v1/videos/{id}/basic-info is free — title, duration, channel, caption languages. Use it as your pre-check before spending credits, exactly like /youtube/info.
  • GET /v1/videos/{id}/video-info costs 1 credit — the complete payload: description, statistics, thumbnails, chapters, heatmap, and richer channel fields.
# Free pre-check: what caption languages exist?
curl -H "Authorization: Bearer YOUR_KEY" \
  "https://api.ytapi.dev/v1/videos/dQw4w9WgXcQ/basic-info"

6. Pagination

Both use continuation tokens, with near-identical naming:

TranscriptAPIYTAPI
Request: continuation=<token>Request: continuation=<token> (or cursor=)
Response: continuation_token, has_moreResponse: continuation / next_cursor, has_more

Your pagination loop needs only field-name tweaks.

7. Errors, retries, and rate limits

TranscriptAPIYTAPI
Rate limit300 req/min per keyFree: 1 req/s and 100 requests/day (200 credits). Paid: 300 / 600 / 3,000 RPM by pack
Rate-limit headersX-RateLimit-Limit/Remaining/Reset, Retry-After on 429Retry-After, X-RateLimit-Limit on 429
Credit exhausted402 insufficient_credits402 insufficient_credits (same semantics)
Retryable408, 429, 503 (1–5s backoff, 2–3 tries)429, 503, upstream 5xx
No captions404 (+ available_languages hint)4xx captions_disabled / language_not_found
Error shape{detail, code}{error: {code, message}}

Notable: the 402-insufficient-credits contract is identical, so your "top up and retry" logic ports over unchanged. Only the error envelope shape differs.

One billing difference in your favor: TranscriptAPI's free /youtube/info-style pre-check requires an account with at least 1 valid credit; YTAPI's free basic-info lookup and free search suggestions have no such requirement.

8. Batch workloads

TranscriptAPI has no batch endpoint — if you were looping over videos client-side, YTAPI's POST /v1/batch (up to 100 tasks per job, GET /v1/batch/{id} to poll) will simplify your code and cut round-trips. Each successful transcript or basic_info task costs 1 credit. A single GET /v1/videos/{id}/basic-info outside a batch costs 0.

Checklist

  • Swap base URL, keep Authorization: Bearer
  • video_url= → video_id= (extract ID if you pass full URLs)
  • format=json → format=segments; transcript → segments in response parsing
  • length_seconds → duration_seconds
  • language= → languages=; asr-<code> → track_policy=asr_first
  • send_metadata → GET /v1/videos/{id}/basic-info (free)
  • Update error parsing to {error: {code, message}}
  • Pagination: continuation_token → continuation/next_cursor

FAQ

Do I need to change authentication?

No. Both use a Bearer token in the Authorization header. Swap the key and the base URL.

Can I test before switching?

Yes. YTAPI gives you 200 free credits without a card, and only successful responses use them, so you can run your own list of videos through both APIs and compare.

Are failed requests billed?

Not on YTAPI: only HTTP 200 responses use a credit. Videos without captions (404), rate limits (429) and server errors are free. TranscriptAPI doesn't bill 404 or 408 either.