Using the API
Rate limits
Every API key has a fixed request budget per minute. Budgets are generous for
well-behaved integrations: with ETags, updated_since, and full pages,
a recurring sync rarely spends more than a few requests.
The budgets
| Budget | Limit | Applies to |
|---|---|---|
| Per key | 120 requests / minute | Each pk_live_ key independently |
| Per account | 240 requests / minute | All of an account's keys combined |
Both budgets are enforced: a single key can never exceed 120/minute, and all keys of an account together can never exceed 240/minute — splitting traffic across keys raises the ceiling only up to the account budget.
Read your remaining budget
Every response carries the current rate-limit state:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | The per-key budget for the current window |
X-RateLimit-Remaining | Requests left in the window |
X-RateLimit-Reset | When the window resets (unix seconds) |
Retry-After | On 429 only: seconds to wait before retrying |
When you hit the limit
Over-budget requests fail with 429 and the
standard error envelope, code rate_limited:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
{"error": {"code": "rate_limited", "message": "...", "request_id": "req_..."}}
- On
429: waitRetry-Afterseconds, then retry the same request. - On
5xx: retry with exponential backoff and jitter. - Other
4xxresponses are not retryable unchanged — fix the request first.
Keep syncs nearly free
- Full pages. Ask for
limit=250(the maximum) instead of walking many small pages. - Conditional reads. Send the last
ETagback asIf-None-Match; a304costs no bandwidth and tells you nothing changed. - Incremental polling. Pass
updated_sinceso unchanged entities never appear in the page at all.
One GET /api/v1/products?limit=250&updated_since=... per resource you mirror is usually the whole poll — see the sync guide for the full pattern.