Rate limits
Picked limits how many calls a workspace can make per minute. This page gives the limits, the headers that show where you stand, and how to wait and retry.
The limits
| Endpoints | Limit |
|---|---|
GET /api/v1/stock, GET /api/v1/stock/changes and GET /api/v1/stock/changes/feed |
200 requests per minute |
| Every other endpoint | 60 requests per minute |
The limits count per workspace, not per token: every token of your workspace draws from the same budget. The stock endpoints have a budget of their own, so polling stock never uses up the budget your order import needs. A step's callback takes no token and isn't limited while it names a step that waits for it; only callbacks to an address no step waits on (a 404) count, per IP address.
Every call counts, including calls that fail and dry runs.
The headers
Every response to an authenticated call tells you where you stand:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
The limit that applies to this call, per minute. |
X-RateLimit-Remaining |
How many calls are left in the current minute. |
Past the limit, Picked answers 429 with the code rate_limited, and two more headers:
| Header | Meaning |
|---|---|
Retry-After |
How many seconds to wait before calling again. |
X-RateLimit-Reset |
When the limit resets, as a Unix timestamp. |
Staying under the limit
- Read stock in bulk.
GET /api/v1/stock?skus=A,B,Ctakes up to 100 SKUs in one call, so you don't need one call per product. - Spread the work. Send a batch of orders at an even pace that stays under the limit, rather than all at once. Sent all at once, most of it is refused.
Waiting and retrying
When a call answers 429, wait the number of seconds in Retry-After and try again. When it answers 503 or 500, wait a moment and double the pause on each new attempt. Give up after a few attempts and report the failure, rather than retrying forever.
A sketch in JavaScript (Node.js 18 or later):
async function callPicked(url, options = {}, attempts = 5) {
for (let attempt = 1; ; attempt++) {
const response = await fetch(url, {
...options,
headers: {
Authorization: `Bearer ${process.env.PICKED_TOKEN}`,
Accept: 'application/json',
...options.headers,
},
});
const retryable = [429, 500, 503].includes(response.status);
if (!retryable || attempt === attempts) {
return response;
}
const retryAfter = Number(response.headers.get('Retry-After'));
const seconds = retryAfter > 0 ? retryAfter : 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}
}
Retry a write only when Picked can recognise the repeat. See Idempotency.