Rate limits
At the end of this guide your app stays within its limits and backs off correctly when it does not.
The limits
| Scope | Requests per minute |
|---|---|
| One connection (one business) | 600 |
| Your whole app, across every connection | 3000 |
| The token endpoint, per app, counting only requests that authenticate as the app | 60 |
| The token endpoint, per calling address, whatever app is named | 600 |
Both the connection limit and the app limit apply to every request. A busy integration with many businesses meets the app limit first; spread work across the minute rather than syncing every business at once. Each connection also renews on its own against the token endpoint, so stagger renewals rather than renewing every connection together.
The headers
Every v1 response carries the connection's allowance in the standard RateLimit and RateLimit-Policy headers.
RateLimit: limit=600, remaining=598, reset=42
RateLimit-Policy: 600;w=60
Shiftly-Request-Id: req_66f1c2a4b3d9e8f7a6b5c4d3
Shiftly-Version: v1reset is the number of seconds until the window starts again.
When you go over
The request is refused with 429 and the code rate_limited. The reset value in the RateLimit header says exactly how many seconds until you can send again; the Retry-After header is the length of the whole window, 60 seconds, which is never too short. Nothing about the request was processed, so retrying it after the wait is safe.
{
"error": {
"code": "rate_limited",
"message": "Too many requests. Wait before trying again.",
"request_id": "req_66f1c2a4b3d9e8f7a6b5c4d4"
}
}Use fewer requests
- Create up to 100 shifts or timesheets in one request by sending data as an array. One request, one rate-limit unit.
- Read with updated_since instead of re-reading whole lists.
- Use the largest page size, 200, when you do read a whole list.
- Read totals and labour costs instead of paging through every timesheet and shift.
