/api/v1, and both are counted per calling IP
address over a rolling one minute window.
There are 65 resource families, each with its own family bucket. Products, orders,
customers, inventory, pricing, discounts, webhooks and so on each count separately.
Why both limits exist
The per-family budget stops one workload starving another. A catalogue sync hammering products cannot throttle an unrelated integration that only reads reviews. The global ceiling bounds the total you can extract, which per-family limits alone cannot do. Without it a caller simply multiplies their budget by the number of families, and 65 families at 120 each is 7,800 requests a minute.The global ceiling is deliberately higher than the per-family figure. If both were
120 the outer limit would always bind first and the per-family buckets would never
do anything.
Budget headers
Every response, not only a refusal, tells you where you stand:RateLimit-Reset is delta seconds, not a unix timestamp. Sleep for that many
seconds. You do not need your clock to agree with ours.
When the two limiters stack, the headers describe whichever one is binding: the
smaller remaining wins. So RateLimit-Remaining: 3 means three more requests, whether
that came from your family budget or the global ceiling. All three fields move
together, so a response never describes half of one limiter and half of another.
Being refused
Over budget returns429 with the standard envelope, plus Retry-After in whole
seconds:
Retry-After is rounded up and never below 1. A Retry-After: 0 would tell a client
to retry immediately into a refusal it is guaranteed to hit again, turning a rate limit
into a hot loop against the thing it was meant to protect.
Backing off correctly
1
Honour Retry-After
Sleep for exactly the seconds given. Do not retry sooner, and do not use a fixed
one second sleep, which will simply be refused again.
2
Add jitter
If you run several workers, add a random fraction of a second so they do not all
wake at the same instant and re-trigger the limit together.
3
Watch RateLimit-Remaining and slow down before you are refused
Throttling yourself at a low remaining is cheaper than being refused and retrying.
A sync loop that pauses at
RateLimit-Remaining: 5 never sees a 429 at all.4
Page with a larger limit
?limit=100 fetches five times as many records per request as the default 20, for
the same one request against your budget. Most rate limit problems on a bulk read
are really a paging size problem.Failed authentication is limited separately
Repeated bad credentials are counted in their own bucket, independent of your request budget. A key that has been revoked or mistyped will start being refused for rate limiting rather than authentication if you retry it in a loop. Fix the credential rather than retrying it.A 429 does not consume your idempotency key
If a write is refused for rate limiting, theIdempotency-Key you sent is released
rather than spent. Retry the same operation with the same key once your window
resets. See Idempotency.