Rate limits
Per-key and per-IP request limits, the 429 response shape, and how to batch so you stay well below them.
Limits protect the platform during busy race weekends. They are applied per instance and held in memory, so treat the numbers below as guidance for sensible clients rather than a hard guarantee.
Limits
| Endpoint group | Keyed by | Per minute | Per hour |
|---|---|---|---|
| Ingest laps, penalties, session status | API key | 120 | 3,000 |
| Stream (RMonitor lines, passings) | API key + event | 300 | 12,000 |
| Feed status heartbeat | API key + event | 120 | 3,000 |
| Public reads (leaderboard, laps, feed) | Client IP | 600 | 30,000 |
| Track API (all endpoints) | API key | 120 | n/a |
The 429 response
Live Timing endpoints return how long to wait, in both a header and the body:
HTTP/1.1 429 Too Many Requests
Retry-After: 17
Content-Type: application/json
{ "error": "rate limit exceeded", "scope": "minute", "retry_after_s": 17 }
scope is minute or hour, telling you which window you exhausted. The Track API returns 429 with { "error": "rate limit exceeded" } and no Retry-After; wait up to a minute before retrying.
Staying under the limits
-
Batch laps.
Send 50 to 200 laps per request to
POST /lapsrather than one per request. The cap is 1,000 laps per request, so even a full session fits in a handful of calls. -
Prefer the stream endpoint for live feeds.
POST /streamhas the highest ceiling because it’s designed for continuous feeds. The timing bridge uploads once a second by default and batches up to 2,000 lines per request. -
Back off.
On
429, waitRetry-Afterseconds. On5xx, use exponential backoff with jitter. -
Cache public reads.
Leaderboards change at most once per lap. Poll every few seconds, not every few hundred milliseconds, and share one poller across viewers.