Rate limits
Each key has its own limit of requests a minute, 60 unless you raise it. Every reply tells you how many you have left.
The per-key limit
- Each key may make 60 requests a minute by default, counted over the last 60 seconds (a rolling window, not the clock minute).
- Raise it per key in Setup > API keys, under Expiry, rate limit, sites and browser origins: 60 to 120 requests a minute. A TempClock super admin can set up to 600 for a busy feed.
- Limits are per key, so one busy integration never slows another. Requests sent at the same moment are counted in the order they arrive, so a parallel burst gets exactly what is left of the limit through and the rest get 429: never more, and never fewer.
- Refused requests (429) do not count, so a client that backs off recovers at once.
Headers
Every reply to a recognised key (successes and errors, including a revoked or expired key) carries:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 57
A 429 adds Retry-After, in seconds. A reply to a request with no key or an unknown key has no X-RateLimit-* headers, and carries Retry-After only when it is a 429. A browser page (with its origin on the key) can read all of these headers.
Going over
Over the limit the API answers 429 with error_code: rate_limited and Retry-After: 60. Wait that long, or until X-RateLimit-Remaining would be above 0, then carry on. Nothing in the refused request was done.
Over the key's rate limit (this key allows 1 request a minute) 429
Key used: a key with a limit of 1 request a minute.
Request
curl -s "$TC_BASE/locations.php" \ -H "Authorization: Bearer $TC_KEY"
Real reply (local test copy, fake demo data)
HTTP 429 Retry-After: 60 { "error": true, "message": "Rate limit exceeded. Maximum 1 requests per minute.", "status": 429, "error_code": "rate_limited" }
Unknown keys
An address that sends 20 unknown keys in 5 minutes gets 429 rate_limited for any further key that does not work, with Retry-After set to when the window clears. This protects real keys from guessing. A key that works is never held back by it, so other callers on a shared address (an office network or an integration platform) cannot block your integration. If you hit it, check the key was copied in full: the API Logs page flags refused keys that start like one of yours.
Page sizes and periods
| Endpoint | Most per request |
|---|---|
| Every list | limit 100 (default 50) |
/payroll.php | limit 200 lines; 26 pay weeks per request |
/pay-weeks.php | 26 pay weeks (default: the current week and the 7 before it) |
/charges.php, /exceptions.php | 93 days |
/timesheets.php with payroll_status | 2,000 matching shifts before paging (narrow with dates) |
/availability.php who is free | A slot of up to 24 hours |
Throughput for a clock feed
A third-party terminal or turnstile sends one request per clock. At the default 60 a minute, 450 workers arriving for one shift change take about 7.5 minutes to send. Two things keep that accurate and fast:
- Send the real time. Put the moment the worker badged in
occurred_at. TempClock records that time (up to 15 minutes back), so a queue at the gate never changes anyone's hours. A clock more than 60 seconds back is flaggedapi_backdatedfor review on the Exceptions page. - Raise the key's limit. At 120 a minute the same 450 clocks take under 4 minutes; at 600 (set by a TempClock super admin) under a minute.
Queue clocks at the terminal, send them in order with an Idempotency-Key each (so a retry after a network drop never clocks twice), and slow down when X-RateLimit-Remaining runs low. A clock queued for more than 15 minutes is refused (400 validation_failed, field occurred_at) and should be added by hand in TempClock.
Staying well inside the limit
- Use webhooks instead of polling: TempClock tells you when a week is locked or a shift is approved.
- Sync with updated_since rather than reading every record again.
- Cache lookups (sites, departments, cost codes): they change rarely.
- Ask for the most rows per page you can use (
limit=100). - Use one key per system, so a busy system has its own limit.