Rate Limits
Four tiers, all per minute, all enforced. Which one applies to a request is decided by the credential it carries, and every response tells you which ceiling you are working against.
The four tiers
10 requests per minute60 requests per minute300 requests per minute10,000 requests per minuteThe last row is a ceiling across every key and every IP reaching one brand. It is not a per caller limit, and a busy brand can exhaust it for everyone.
There is no daily limit. There is no monthly limit either, and no request quota of any kind beyond these four buckets. If you read a daily figure somewhere, it was wrong: this site published one until 2026-09-16.
Confirm it yourself, in one command
Do not take the table above on trust. Every storefront response carries the ceiling it was checked against, so the server will tell you directly whether this page is current.
curl -sI "https://cresva.ai/api/storefront/$BRAND_ID/products" | grep -i ratelimitx-ratelimit-limit: 10
x-ratelimit-remaining: 3
x-ratelimit-reset: 1789499641That is the anonymous tier, because the request carried no credential. Send a key and the limit reported changes to that key's tier. The CI live job runs this command against the live API on every push and fails if the header and this page disagree.
Rate limit headers
X-RateLimit-LimitintegerThe ceiling this request was checked against. This is the real enforced number for the credential you sent, not a plan value.X-RateLimit-RemainingintegerRequests left in the current window.X-RateLimit-ResetintegerUnix timestamp, in seconds, when the window resets.Retry-AfterintegerSeconds to wait. Sent on a 429 and on a 503, and on nothing else, so do not expect it on a successful response.429 Too Many Requests
Over the limit, the API returns 429 with a Retry-After header. Wait that long before sending another request.
{
"error": {
"code": "rate_limited",
"message": "Rate limited"
}
}503, and why it is not a 429
If the limiter itself cannot be reached, the request is refused with a 503 rather than served unmetered. It is deliberately not a 429: you have done nothing wrong and the fault is ours. A 429 would tell a well behaved agent to back off for something it did not do, and would be indistinguishable from genuinely overrunning.
Working within them
- Read
X-RateLimit-Remainingand slow down before you hit zero, rather than backing off after a 429. - Cache. Catalogue responses are served with
Cache-Control: public, max-age=3600, so a product listing can be reused for an hour. - Use a key. Anonymous is 10 per minute and a public key is 60, which is six times the room for the cost of sending a header.
- Spread requests rather than bursting. The window is a minute, so a burst of 11 anonymous requests in one second should be a 429 even if you then wait a minute. That follows from the limit rather than from a run anybody has recorded.
- Expect a stale counter on a repeated identical GET. Those are served from CDN cache and never reach the limiter, so
X-RateLimit-Remainingcan sit still, or go up, across requests you know you made. Vary the query string to watch it move. - Subscribe to webhooks instead of polling for changes you care about.