# Rate limits

> Source: https://pixelsystems.com/docs/api/rate-limits


How the API rate limits requests, which headers to read, and how to handle rate-limited responses.

## Policy

Every `/v1` endpoint is rate limited **per API key**. When you exceed the limit, requests return [`429 Too Many Requests`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/429) until the limit resets. The exact limits may change over time, so do not hard-code them: read the rate limit headers on each response to see your current budget, and design clients to back off on `429`.

The limit applies to requests, not files: one [Assess a file](https://pixelsystems.com/docs/api/assess) (`/v1/assess`) call counts once, whether it carries one file or 20. A job-flow call also counts once.

## Rate limit headers

Every response includes the current limit and how many requests remain in the window, following the [IETF RateLimit headers draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/). The values are your key's own budget, so read them rather than assuming a figure; for example:

```text
RateLimit-Limit: 120
RateLimit-Remaining: 87
```

A rejected request additionally carries a [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) header with the number of seconds until the window resets.

## Handling 429 responses

A rate-limited response uses the standard [`ApiError`](https://pixelsystems.com/docs/api/resources#apierror) envelope with the [error code](https://pixelsystems.com/docs/api/error-codes) `rate_limited` and a `retryAfter` field mirroring the header:

```json
{
  "code": "rate_limited",
  "message": "Rate limit exceeded. Please retry later.",
  "retryAfter": 42
}
```

Wait `retryAfter` seconds before retrying rather than retrying immediately. For [Assess a file](https://pixelsystems.com/docs/api/assess) (`/v1/assess`), send an [`Idempotency-Key`](https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/) so a retried upload never creates a duplicate job. To reduce request volume while waiting for results, prefer `?wait=true` long-polling on [Get a job's result](https://pixelsystems.com/docs/api/get-job) (`/v1/jobs/{jobId}`) over tight polling loops.
