> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ventry.es/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limits

> Quotas, headers and how to behave on a 429.

Limits are counted **per API key**, not per IP. Two integrators behind the same
proxy do not penalise each other.

| Endpoint kind                                   | Default quota       |
| ----------------------------------------------- | ------------------- |
| Reads (`GET`)                                   | 120 requests/minute |
| Ticket writes and top-ups                       | 20 requests/minute  |
| Accreditation (`POST /tickets/{code}/check-in`) | 60 requests/minute  |
| Zone validation (`POST /access-checks`)         | 120 requests/minute |

The general quota is configurable per key: if your integration needs more, ask
the organiser and they can raise it from the dashboard.

## Headers

Every response carries:

```http theme={null}
x-ratelimit-limit: 120
x-ratelimit-remaining: 87
x-ratelimit-reset: 34
```

Once exhausted, the response is `429` with `retry-after` in seconds:

```http theme={null}
HTTP/1.1 429 Too Many Requests
retry-after: 26
```

```json theme={null}
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Has superado el límite de peticiones. Reinténtalo en 26 segundos.",
    "request_id": "req_9f2c1a4e7b304d51"
  }
}
```

<Tip>
  Do not invent your own wait: use the `retry-after` value. The server knows
  exactly when your quota frees up.
</Tip>

## How not to hit the limit

<AccordionGroup>
  <Accordion title="Batch your ticket creation">
    `POST /tickets` accepts up to **500 tickets per call**. Loading 5,000 tickets
    is 10 calls, not 5,000. With a write quota of 20 calls per minute, that is the
    difference between half a minute and four hours.
  </Accordion>

  <Accordion title="Raise the limit on reads">
    Lists accept `limit=200`. Walking 10,000 sales becomes 50 calls instead of
    200\.
  </Accordion>

  <Accordion title="Sync incrementally">
    Do not pull the whole history on every pass. Use `updated_since` and `since`
    as explained in [Pagination](/en/pagination).
  </Accordion>

  <Accordion title="Do not poll aggressively">
    Checking ticket state every second does not give you fresher information than
    exists: terminals sync in batches. Every 30 seconds is more than enough during
    the event.
  </Accordion>
</AccordionGroup>

## Operational note

The counter lives in the memory of the process serving the request. On a
single-instance deployment — the usual case — it is exact. If the event is served
from several instances, the effective quota may be somewhat higher than the
nominal one. Never lower, so there is nothing you need to do about it.
