Rate limits
Rate limits are applied per app, per environment. Your app’s exact limits
are shown in the console under Apps → Usage → Rate limits;
the defaults are generous enough that a well-behaved integration never sees a
429:
| Surface | Default limit |
|---|---|
| API requests, per app | 300 requests / minute |
| Full menu push, per store | 12 / hour |
| Availability batch, per store | 60 / minute |
| OAuth token and refresh calls, per app | 60 / minute |
Limits are enforced with a sliding window. Bursts within the window are fine; sustained traffic above it is not.
The 429 response
Section titled “The 429 response”When a limit is exceeded, the request is rejected with the standard
error envelope and a Retry-After header giving the number
of seconds to wait:
HTTP/1.1 429 Too Many RequestsRetry-After: 23Content-Type: application/json
{ "error": { "code": "rate.limited", "message": "Rate limit exceeded. Retry after 23 seconds." } }Honour Retry-After exactly — retrying earlier extends the window and delays
your own recovery.
Staying under the limit
Section titled “Staying under the limit”- Retry with exponential backoff and jitter on
429and5xx. Start at theRetry-Aftervalue (or 1 second), double per attempt, add random jitter, cap around 60 seconds, and cap total attempts. - Cache tokens. One access token per merchant, reused for its full hour, refreshed 60 seconds early — see Authentication. Minting a token per request is the most common way integrations rate-limit themselves.
- Push menus on change, not on a timer. A full menu push is the heaviest
call on the platform. Push when the catalogue changes and when Quiqqy asks
via
action_required— not every few minutes. Use the batch and availability endpoints for small deltas. - Batch availability changes. One call with fifty items beats fifty calls with one item.
- Never poll for orders. Orders arrive over webhooks; polling adds load and latency and gains nothing.