Skip to content

Rate limits and quota

Two separate counters guard the API.

  • Rate limit: requests per minute, per key. Smooths bursts.
  • Quota: requests per billing period, per key. Sets the plan.

Both are enforced at the edge, before a request reaches the index, so a rejected call is cheap for both of us.

Reading the headers

Every response carries the state of the minute window:

HeaderMeaning
X-RateLimit-LimitRequests allowed in the window
X-RateLimit-RemainingRequests left in it
X-RateLimit-ResetUnix seconds when the window rolls over
Retry-AfterSeconds to wait. Present on 429 only

Period quota is not in the headers, because it changes too slowly to be worth a byte on every response. Read it from GET /usage, which does not count against either counter.

When you cross a limit

Both cases answer 429. The code tells them apart:

json
{ "error": { "code": "rate_limited", "message": "120 requests per minute exceeded", "retryAfter": 27 } }
  • rate_limited: the minute window. Wait retryAfter seconds and repeat the same request.
  • quota_exceeded: the period. Retrying will not help until periodEnd, or until the plan changes. Treat it as a state, not a transient error, and stop the loop.

Retry rate_limited with exponential backoff and jitter. A fleet that all retries at Retry-After exactly rebuilds the same spike it just caused.

Plans

PlanForPer monthPer minute
TrialSelf-serve, free. Enough to try every endpoint and decide.2060
StarterA single app or site in production. Write to us.not publishednot published
GrowthHigher volume, several products under one account.not publishednot published

Quota is counted per account, not per key. Creating a second key separates your environments; it does not double your allowance.

Paid plan numbers and pricing are not published yet. Write to [email protected] with your expected volume.

Staying under them

The index changes once a day at most. Almost every integration that hits a limit is asking the same question repeatedly:

  • Cache word lookups. A word's clip list is stable for hours, see Caching.
  • Store clipId and videoId on your side after the first lookup. Clip metadata and transcripts are immutable for a given clip.
  • Fetch transcripts once per clip, not once per viewing.

Metadata only. Playback runs on YouTube, through your own embed.