SeatLayer limits a few routes so one caller cannot starve others. Selling has no request budget, and most other Server API routes have none either. Each limit below is a fixed window: the count starts with the first request and resets when the window ends.
Selling has no request budget
Your server can sell as fast as buyers arrive. These routes are never refused for rate, whatever one secret key sends:
- Event holds:
POST /v1/events/:key/hold,/extend,/release,/book,/best-available,/best-available-bookand/best-available-block. - Season selling:
POST /v1/seasons/:key/buyer-access-sessionsand its revoke,GET /v1/seasons/:key/holds/:operationId,POST …/book,GET /v1/seasons/:key/bookings/:actionIdandPOST …/cancel. - Season renewals:
POST /v1/seasons/:key/renewal-offers/:offerId/intent,/checkoutand/commit, andPOST /v1/holders/:holderRef/renewal-offers/:offerId/checkout.
Inventory stays protected without a budget. A hold has a time limit and a limit of 100 seats, and nothing sells while sales are closed. Buyer routes called from a browser keep their per-IP budgets (below).
Server API budgets
| Budget | Limit | Counted per | Applies to |
|---|---|---|---|
| Seasons API | 600 per minute | Secret key | Season setup, operations, renewal offers, holders and reports on /v1/seasons/*; /v1/holders/*, /v1/customers and /v1/orders; POST /v1/webhooks/:id/rotate-secret. The selling routes above are not counted |
| Manage sessions | 300 per minute | mse_… token |
Every route called with an event manage token |
| Panorama manifests | 10 per day | Account and chart | POST /v1/charts/:chartId/panorama-manifests |
| Readiness | 30 per minute | IP address | GET /health/ready |
Season routes called from a signed-in dashboard session skip the Seasons API budget.
The readiness limit is approximate, so treat it as a rough guard for health checks, not an exact number.
Buyer and public budgets
These routes are called from browsers, so they are counted per IP address.
| Budget | Limit | Counted per | Applies to |
|---|---|---|---|
| Buyer holds | 120 per minute | IP address | Hold and Best Available calls on /pub/* |
| Buyer reads | 3,000 per minute | IP address | Seat map and availability reads on /pub/* |
| Season buyer sessions | 30 per minute | IP address and Season | POST /pub/seasons/:key/sessions |
| Performance Group buyer sessions | 30 per minute | IP address and group | POST /pub/performance-groups/:key/sessions |
| Season renewal links | 60 per minute | IP address | /pub/season-renewals/* |
A buyer session is counted per IP and per Season or group, so many buyers behind one office or venue network do not lock each other out of different events.
The 429 response
A refused request answers 429 Too Many Requests:
{
"error": "rate_limited",
"code": "rate_limited",
"retryAfterSeconds": 12
}Retry-After: 12
RateLimit-Limit: 600
RateLimit-Remaining: 0
RateLimit-Reset: 12
RateLimit-Policy: 600;w=60Some details differ by route:
- Manage-session and panorama responses send
Retry-Afteronly, without theRateLimit-*headers. - The readiness check sends
{"error": "rate_limited"}with no headers. - Browsers can read
Retry-Afteracross origins. TheRateLimit-*headers are visible to server callers only.
How to back off
- Wait for
Retry-Afterseconds, orretryAfterSecondswhen the header is missing, before trying again. Do not retry in a tight loop. - A 429 means the request did nothing: no hold was created and no seat changed. Retrying after the wait is safe.
- An on-sale through your own server needs no pacing: the selling routes have no budget. Poll a pending Season booking every few seconds rather than every second; polling faster does not book it sooner.
- Use separate keys for separate systems. A reporting job on the same key as your Season setup competes for the Seasons budget.
- Cache reads. Event lists, charts, and reports have no budget, but polling them every second adds load without new data. Use webhooks to learn about changes.
For how SeatLayer keeps inventory consistent when many buyers race for the same seats, see concurrency and performance. For every error code, see API errors.