# Rate limits

> **TL;DR** — Each organisation has an abuse ceiling per endpoint counter, far above normal traffic. Playback counts **tickets**, not requests, and refills every second. Near the ceiling Wandura slows down instead of failing: prefetches are refused first, a `play` request may wait half a second, and repeat requests get the ticket already issued. On a `429`, wait `Retry-After`. The numbers: [Canonical API behaviour · Rate limits](https://docs.wandura.ai/developers/reference/behaviour#rate-limits).

## How it is counted
- **Per organisation**, not per key: more keys do not raise the ceiling.
- **Per counter**: playback, catalog, creatives, open video list, single open video and configuration each have their own, so a runaway job on one cannot block another.
- **In the counter's unit**: playback counts tickets (a batch of 3 counts 3; a reused ticket counts 0; a refused ticket counts 0); the others count requests.
- **Only valid keys** are counted: nobody without your key can use up your ceiling. Anyone who can drive **your** ticket endpoint can, though: limit tickets per viewer on your side ([Security](https://docs.wandura.ai/developers/concepts/security#trust-boundary)).

The limit values per counter, units included, are in one table: [Canonical API behaviour · Rate limits](https://docs.wandura.ai/developers/reference/behaviour#rate-limits). `GET /config` returns the limits that apply to your organisation.

## Refill
| Counters | How the allowance comes back |
|---|---|
| `playback`, `catalog` | **Continuously**: one sixtieth of the limit every second. From idle you can spend a full minute's worth at once; after that, room comes back second by second, so `Retry-After` is usually **1–2 seconds**. |
| `creatives`, `videos`, `video`, `config` | **Per clock minute (UTC)**: the count starts again at every whole minute; `Retry-After` is the rest of the minute. |

Counting is approximate on the high side: a burst can get up to about 2.5 % past a limit before the `429` starts.

## Graceful overload
Close to the playback ceiling, Wandura protects the episode a viewer has just tapped:

| Situation | What happens |
|---|---|
| Less than about 20 % of your playback allowance left | Requests with `"intent": "prefetch"` get `429` `rate_limited` with `"reason": "prefetch_shed"`. `play` requests are still issued. |
| A batch with more items than there is room for | Prefetch items are refused first, each with its own `429` and `retry_after`; the others get tickets. The request is `429` as a whole only when no item can be issued. |
| A `play` request arrives a few hundred milliseconds before there is room | Wandura holds it up to about **0.5 seconds**, then issues it. Allow at least 5 seconds of client timeout. Prefetches are never held. |
| The same viewer asks again for the same episode on the same device | The ticket already issued comes back, not counted (needs `viewer_ref`; see [Playback](https://docs.wandura.ai/developers/concepts/playback#viewer-ref)). |

A paused prefetch answers:

```json
{
  "error": "Prefetch requests are paused while your playback traffic is close to its ceiling — tickets for viewers who pressed play are still issued. Retry the prefetch after Retry-After, or request it when the viewer plays.",
  "error_code": "rate_limited",
  "reason": "prefetch_shed"
}
```

It is not an error for the viewer: request the episode with `"intent": "play"` when the viewer taps it.

## When you reach the ceiling
Every endpoint answers `429` with a flat body, the creatives endpoints included:

```json
{
  "error": "Too many catalog requests for this account. This is an abuse ceiling, not a quota — if a normal integration reaches it, contact us and it will be raised.",
  "error_code": "rate_limited"
}
```

| Header (on `429` only) | Meaning |
|---|---|
| `Retry-After` | Seconds until there is room again. |
| `X-RateLimit-Limit` | The limit of this counter for your organisation, per window (playback: tickets). |
| `X-RateLimit-Window` | The window, in seconds (60). |

## How to recover
1. Stop sending to that counter until `Retry-After` has passed, plus a random 0–1 s. Earlier retries only earn more `429`s.
2. Find the cause: a retry loop without backoff, a job that requests tickets for a whole catalog, catalog calls on every app launch.
3. If your **normal** traffic reaches a ceiling, ask in your team's Wandura Discord channel to raise it for your organisation. A raised limit takes effect within about a minute.

Wandura monitors organisations that reach their playback ceiling. Still tell Wandura in your channel when your normal traffic does: that is how a limit gets raised.

Retry rules for every answer: [the retry policy](https://docs.wandura.ai/developers/reference/behaviour#retries).

## Related
- [Smooth playback under load](https://docs.wandura.ai/developers/guides/smooth-playback)
- [Go-live checklist](https://docs.wandura.ai/developers/production/go-live): the limit review before launch.
