---
title: Rate limits & fair use
description: The published request ceiling per credential and how to stay under it.
section: Core concepts
order: 4
---

# Rate limits & fair use

FlickList caps how many requests a single credential can make per hour, so build your client to stay under it instead of discovering the ceiling in production.

```json
{
  "error": "rate_limited"
}
```

```
Retry-After: 60
```

The published limit is 1,000 requests per hour per credential (a session token or an API key). This is a fair-use ceiling. When you exceed it, the response is `429` with a `Retry-After` header telling you how many seconds to wait. Honor that value before your next request instead of retrying immediately or backing off on a schedule of your own:

:::tabs
```bash
retry_after=$(curl -sD - -o /dev/null "$URL" | grep -i '^retry-after:' | tr -dc '0-9')
sleep "$retry_after"
```
```javascript
const res = await fetch(url, { headers });
if (res.status === 429) {
  const retryAfter = Number(res.headers.get('retry-after'));
  await new Promise((r) => setTimeout(r, retryAfter * 1000));
}
```
```python
import time
if r.status_code == 429:
    time.sleep(int(r.headers["Retry-After"]))
```
:::

| Traffic pattern | Approximate requests/hour |
| --- | --- |
| Per-credential ceiling | `1,000` |
| Scrobble heartbeat, one active session | `60` to `120` |

## Check before you fetch

The most common way to reach the ceiling is polling large collections on a timer whether or not anything changed. Before re-fetching any collection wholesale, check [`GET /v3/sync/last_activities`](/dev/sync/up-next). It returns a timestamp per data domain (watchlist, ratings, history, and so on) for a fraction of the cost of a full fetch. Compare those timestamps to what you last stored and only pull the collections that actually moved. That's the intended pattern for keeping a client in sync without walking every page of every collection on every poll.

## Scrobble heartbeats fit comfortably

If you're building a player integration, re-posting `start` every 30 to 60 seconds while something plays is expected behavior, not something to budget carefully around. That cadence works out to roughly 60 to 120 requests per hour for a single active playback session, well under the 1,000/hour limit even alongside other traffic your client sends.

> [!WARNING]
> Retrying immediately after a 429, or on a fixed interval that ignores `Retry-After`, only extends your own back-off. Read the header value every time; it can change between responses.
