API reference
AOA public API rate limits per endpoint: 60 requests per minute without a key and 600 with one, X-RateLimit-* headers, Retry-After and handling 429.
Limits are counted over a sliding window. Reading is generous, writing is stricter: reservations and payments touch real seats and real money.
| Request | Limit | Counted per |
|---|---|---|
| Reading venues and events without a key | 60 requests per minute | IP address |
| Reading venues and events with a key | 600 requests per minute | key |
POST/reservations | 60 requests per minute | key |
POST/table-reservations | 60 requests per minute | key |
POST/checkout | 20 requests per 10 minutes | key |
GET/orders/{paymentId} | 600 requests per minute | key |
A key raises the limit tenfold
Send it even where a key is optional: 60 requests per minute from one IP run out fast if your server serves several users at once.The order status limit is deliberately high, the same level as for reading events. Polling the status every 5–10 seconds is perfectly fine.
Every response carries the current state of the limit:
HTTP/1.1 200 OK
RateLimit-Policy: "default";q=600;w=60
RateLimit: "default";r=597;t=60
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 597| Header | Meaning |
|---|---|
RateLimit-Policy | Quota: q requests per window of w seconds (IETF RateLimit draft) |
RateLimit | Quota state: r left, t seconds until it refills. The window slides, so t is an upper bound |
X-RateLimit-Limit | How many requests the window allows |
X-RateLimit-Remaining | How many are left until the window ends |
Retry-After | How many seconds to wait before retrying. Only comes with 429 |
The request returns 429 with the code rate_limited:
HTTP/1.1 429 Too Many Requests
RateLimit-Policy: "default";q=600;w=60
RateLimit: "default";r=0;t=42
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
Retry-After: 42
{
"error": {
"code": "rate_limited",
"message": "Too many requests"
}
}Wait as long as Retry-After says, then retry. Retrying without a pause only extends the block.
async function callApi(url, options, attempt = 0) {
const response = await fetch(url, options);
if (response.status === 429 && attempt < 3) {
const retryAfter = Number(response.headers.get('Retry-After') ?? 1);
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return callApi(url, options, attempt + 1);
}
return response;
}/availability: one response covers every ticket type of the event, so there’s no need to poll each one separately.SUCCESS, FAILED, EXPIRED, REFUNDED.If your integration needs higher limits, write to us and we’ll sort it out.