General

Rate limits

Every response tells you how much budget is left, so a well-behaved client never has to guess.

RateLimit-Limit: 600
RateLimit-Remaining: 587
RateLimit-Reset: 42

RateLimit-Reset is seconds until the window refills. Read these rather than counting your own requests: the budget is shared across every key in the workspace, so your own count is not the whole picture.

Two different refusals

CodeMeansFix
rate_limitedToo many requests too quicklyBack off for Retry-After and spread the work out
quota_exceededThe plan's daily allowance is spentWait for details.resets_at, or upgrade. Retrying sooner will not help.
upstream_rate_limitedA backend refused, not usBack off. The RateLimit headers do not describe this limit.
The allowance comes from the plan

Read it from the entitlements endpoint rather than hard-coding a number. An operator can change it without a release, and every plan has a different one.

Backing off well

  • Honour Retry-After. It is a real number, not a suggestion.
  • Add jitter. Ten workers retrying at the same second reproduce the burst that caused the limit.
  • Slow down before you are refused, when RateLimit-Remaining gets low, rather than after.
  • Batch where the API offers it. One request for fifty things beats fifty requests.