Rate limits
The admin API is rate limited per organization, not per key. Minting a second secret key does not buy a second allowance. Every key an organization holds spends from the same bucket.
Requests you make from the dashboard while signed in are not counted. The limit applies only to requests authenticated with a secret key.
The ceiling
It is a token bucket. Every request spends tokens, and the bucket refills continuously at 10 a second up to its 600 ceiling. An idle integration therefore starts with the full 600 and can spend it as fast as it likes, then settles into 10 requests a second for as long as it keeps going.
Those numbers are sized for the heaviest thing a well-behaved integration does: a one-time migration that reads everything you have. At the maximum page size of 250 records, a 100,000 record catalog is 400 requests, which fits inside a single burst with room to spare. Nothing that walks your data page by page should ever see a 429.
The ceiling is your plan's apiRequestsPerMinute allowance (600 on every plan except
Unlimited, which has 3,000), so it is a number on your organization rather than a constant. GET /organization
returns the value your requests are measured against.
What each endpoint costs
Most endpoints spend one token. The ones that do noticeably more work per request cost more, so a loop over them is bounded by the work it causes rather than by the number of requests it makes.
Each endpoint's cost is on its page in the API reference, and in the OpenAPI
document your store serves at /api/openapi as x-rate-limit-cost on the operation, so you
can plan against it without reading this table.
Reads are charged as well as writes. Paginating a list endpoint without advancing your cursor is the most common way to use up the limit, and counting only writes would miss it.
When you go over
A request that cannot afford its cost gets a 429 and does nothing else. It is not queued and
it is not partially applied.
The response carries a Retry-After header with the whole number of seconds until you can
afford the same request again. Wait that long rather than retrying immediately, because a tighter
retry loop only makes the wait longer for everything else your organization is doing.
The endpoints with their own limits
Two endpoints carry a separate bucket on top of this one, because they are called from your own backend at a different rate:
POST /loyalty-events: a burst of 120, refilling at two a second. This follows your plan'sloyaltyEventsPerMinuteallowance, which is 600 on Unlimited.POST /loyalty-history: a burst of 30, refilling at one a second. It is deliberately tighter than the ceiling would be on its own, so a runaway loop is told which endpoint it exhausted.
These are per organization and per endpoint, so they do not compete with each other. A request to one of them spends from both its own bucket and the organization-wide one.
The widget API
The widget API is limited differently, because it is called from every shopper's browser rather than from one backend of yours.
A request carrying a publishable key is limited per address: each combination of
publishable key and caller address gets a burst of 120, refilling at two a second. That is 120
requests a minute for one shopper, which is a product page firing every widget it has and a
browsing session on top. It is also the limit Shopify documents for its own Storefront API per
buyer address (a 60 second bucket at half a second a request, leaking one a second), so a headless
storefront already stays within it. Going over gets the same 429 with a Retry-After header:
A few storefront actions have a tighter limit of their own on top, again per caller address: asking for an instant answer (20 a minute), voting on whether a review was helpful (10 an hour), and submitting a review or uploading its photos. These apply whichever key the request carries, so a server sending them for many shoppers shares one address's allowance.
Send apiPublishableKey once. A request that names it more than once is refused with a 400.
A request carrying a secret key as a bearer token draws on the organization ceiling above
instead, at one token per request, and takes the place of the apiPublishableKey parameter.
A server rendering pages for many shoppers should use a secret key, not the publishable key. Every call would otherwise come from one address, so your whole storefront would share a single shopper's allowance. See Calling the widget API from a server.
Raising the limit
The ceiling is a field on your organization, so it can be raised for your account without a release. If a legitimate integration cannot fit inside it, get in touch before you start working around it. An import endpoint or a background export job is usually a better answer than a faster loop.