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
| TranscriptAPI | YTAPI | Notes |
|---|---|---|
GET /api/v2/youtube/transcript | GET /v1/transcripts | Core 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=text | format=text | Identical name |
include_timestamp=false | format=text | YTAPI's text format is always plain concatenated text |
send_metadata=true | — | See §4: metadata lives on the video info endpoint |
language=en,es | languages=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'strack_policy:manual_first(default),asr_first, orexact_only. If you were requestingasr-hiexplicitly, uselanguages=hi&track_policy=asr_first. - The response's
languagefield on both APIs is the resolved track code. YTAPI additionally returnstrack_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-infois free — title, duration, channel, caption languages. Use it as your pre-check before spending credits, exactly like/youtube/info.GET /v1/videos/{id}/video-infocosts 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:
| TranscriptAPI | YTAPI |
|---|---|
Request: continuation=<token> | Request: continuation=<token> (or cursor=) |
Response: continuation_token, has_more | Response: continuation / next_cursor, has_more |
Your pagination loop needs only field-name tweaks.
7. Errors, retries, and rate limits
| TranscriptAPI | YTAPI | |
|---|---|---|
| Rate limit | 300 req/min per key | Free: 1 req/s and 100 requests/day (200 credits). Paid: 300 / 600 / 3,000 RPM by pack |
| Rate-limit headers | X-RateLimit-Limit/Remaining/Reset, Retry-After on 429 | Retry-After, X-RateLimit-Limit on 429 |
| Credit exhausted | 402 insufficient_credits | 402 insufficient_credits (same semantics) |
| Retryable | 408, 429, 503 (1–5s backoff, 2–3 tries) | 429, 503, upstream 5xx |
| No captions | 404 (+ 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→segmentsin 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.