One GET request returns the full transcript with timestamps. Routed through residential IPs, so it keeps working after you deploy.
Everyone starts with a library like Python's youtube-transcript-api. It works instantly on a laptop, which is why every tutorial recommends it. Then it goes to a server and starts raising IpBlocked or RequestBlocked on videos you can watch in your browser.
The reason is not your code. YouTube blocks IP ranges belonging to cloud providers, and AWS, GCP, Azure, DigitalOcean and Vercel are all trivially identifiable by ASN. Your home connection is residential and passes. Your server is not and does not.
Fixing it properly means rotating residential proxies with sticky sessions, plus keeping up with the client changes YouTube ships periodically. That is infrastructure and maintenance, not a config flag. This API is that stack, already built and already running in production for Brevyd itself.
curl 'https://brevyd.com/api/v1/transcript?url=https://youtu.be/dQw4w9WgXcQ&text=true' \
-H 'x-api-key: brv_live_...'import requests
r = requests.get(
"https://brevyd.com/api/v1/transcript",
params={"url": "https://youtu.be/dQw4w9WgXcQ", "text": "true"},
headers={"x-api-key": "brv_live_..."},
)
r.raise_for_status()
print(r.json()["content"])const res = await fetch(
"https://brevyd.com/api/v1/transcript?" +
new URLSearchParams({ url: "https://youtu.be/dQw4w9WgXcQ", text: "true" }),
{ headers: { "x-api-key": "brv_live_..." } }
);
const { content, lang } = await res.json();{
"content": "We're no strangers to love, you know the rules...",
"lang": "en",
"availableLangs": ["en", "es", "zh-TW"]
}Endpoint
GET https://brevyd.com/api/v1/transcript
Authentication
x-api-key: brv_live_...
| Parameter | Type | Description |
|---|---|---|
| url | string | Required. YouTube URL or bare video ID. |
| text | boolean | When true, content is a plain string. Default false returns timestamped chunks. |
| lang | string | Optional ISO 639-1 code. Returns 404 rather than silently serving another language. |
| Status | error | Meaning |
|---|---|---|
| 400 | invalid_request | The url parameter was missing or not a YouTube video. |
| 401 | unauthorized | Missing, invalid, or revoked API key. |
| 404 | transcript_unavailable | No caption track for this video. |
| 429 | limit_exceeded | Monthly quota or per-minute rate limit reached. |
| 500 | internal_error | Fetch failed upstream. Safe to retry. |
| Limit | Value | On exceed |
|---|---|---|
| Requests per minute, per key | 60 | 429 limit_exceeded |
| Requests per month, free tier | 50 | 429 limit_exceeded |
| Active keys per account | 5 | 400 on create |
The monthly quota resets on the 1st, UTC. Requests we serve from cache count toward it the same as any other, but they return in a fraction of the time.
Same x-api-key header, same parameters, same response shape with millisecond offsets. Change the base URL and the key. Three differences worth knowing before you switch:
availableLangs can be empty on some responses. We report what the upstream caption list gave us rather than inventing the field.mode parameter. We never AI-generate a transcript, so behaviour is always equivalent to mode=native.202 / jobId path. Every request resolves inline.Free: 50 requests a month
Higher volume plans are not published yet. Rather than invent a number, we are measuring real per-request cost first. Tell us what volume you need and we will size a plan with you.
YouTube blocks IP ranges that belong to cloud providers. AWS, GCP, Azure, DigitalOcean, and Vercel are all publicly identifiable by ASN lookup, so the same call that works on your laptop throws IpBlocked or RequestBlocked from a server. Nothing about your code is wrong; only the IP changed.
It is the same idea, done properly. You need rotating residential proxies with sticky sessions, plus maintenance every time YouTube changes its client. That is a recurring cost and a recurring chore. This endpoint is that stack, already running.
The transcript endpoint uses the same x-api-key header, the same url, text, and lang parameters, and the same { content, lang, availableLangs } response with millisecond offsets. For most integrations, switching is a base-URL change. The differences are listed in the reference below rather than papered over.
You get a 404 with transcript_unavailable. We do not silently fall back to AI transcription and bill you for it, because a surprise charge is worse than a clear error.
Yes: 50 requests a month, no credit card. It is a real free tier, not a trial behind a signup wall.
60 requests per minute per key. If you need more, get in touch.
Not a developer? Use the free transcript tool instead, or read how to get a transcript of a YouTube video.