Rate Limits
How the API protects against abuse.
The API limits requests per client IP address, not per store. Each visitor to your storefront gets their own budget, so a single store can serve an unlimited number of shoppers at once. The limit exists only to stop one client from flooding the API. It never caps your store's overall traffic.
Limits
Every client IP gets its own leaky bucket.
| Scope | Burst | Sustained |
|---|---|---|
| Per IP | 300 requests | 5 requests / second |
A single IP can send up to 300 requests in a burst, then a steady 5 requests per second. A fully drained bucket refills in 60 seconds. Because the bucket is per IP, two different shoppers never share or compete for the same budget.
OPTIONS) requests are not counted.Edge limit
In addition to the per-IP bucket above, a coarser volumetric limit runs at the network edge, before requests reach the API: at most 500 requests every 10 seconds from a single IP. It exists only to absorb floods and sits well above what the per-IP bucket already allows, since a burst of 300 requests that refills at 5 per second works out to at most about 350 requests from one IP in any 10-second window. Normal storefront traffic never approaches it.
If you do trip it, the edge returns its own 429 response directly. That response is not the JSON error envelope described in Errors, and it does not carry the RateLimit-* or Retry-After headers, because it never reaches the API. Keeping publishable-key calls on the client, so each shopper is a distinct IP, keeps you clear of both limits.
Response headers
Every response carries the current state of your IP's bucket, so you can pace requests before you ever hit a 429.
| Header | Description |
|---|---|
RateLimit-Limit | The bucket capacity (maximum burst). |
RateLimit-Remaining | Requests left in the bucket right now. |
RateLimit-Reset | Seconds until the bucket is fully refilled. |
Retry-After | Seconds to wait before retrying. Sent only on a 429. |
The RateLimit-* headers are on every response so you can pace requests before you hit a 429. All four headers are exposed for cross-origin (browser) reads, so storefront JavaScript can read them directly from the fetch response.
Where the limit applies
Publishable keys are meant to be called from the browser, directly from each visitor's device. Used that way every shopper is a distinct IP with a distinct budget, and the limit is effectively invisible at any normal level of traffic.
If you instead call the API from your own server, every request shares that one server's IP, and therefore one bucket. Keep pk_ calls on the client so each visitor is metered independently.
Exceeding the limit
When a single IP goes over the limit the API responds with 429 Too Many Requests and a Retry-After header giving the number of seconds to wait before retrying.
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Too many requests, please try again later"
}
}See Errors for the full error envelope.
Best practices
- Respect the
Retry-Afterheader. Wait the number of seconds it gives before retrying. - Back off and retry instead of looping immediately on a
429. - Cache responses where you can so repeat views do not re-request the same data.