<!-- Source: https://useworkloom.com/dev/rate-limits/ · Workloom API v1 -->

# Rate limits

Limits are per key, so one busy integration cannot slow down another. Every response tells you where you stand.

| What | Limit |
| --- | --- |
| Requests | 300 a minute per key. The count starts again at the start of each minute. |
| Page size | Up to 100 records a page. |

## Headers on every response

| Header | Meaning |
| --- | --- |
| `X-RateLimit-Limit` | Requests allowed in a minute. |
| `X-RateLimit-Remaining` | Requests left this minute. |
| `Retry-After` | Only on a `429`: seconds to wait before retrying (60). |

## Handling a 429

Wait `Retry-After` seconds, then retry the same request. For a POST, send the same `Idempotency-Key` so it cannot run twice.

**Retry with backoff**

```javascript
async function call(url, init, tries = 5) {
  for (let i = 0; i < tries; i++) {
    const res = await fetch(url, init);
    if (res.status !== 429 && res.status < 500) return res;
    const wait = Number(res.headers.get("Retry-After")) || 2 ** i;
    await new Promise((r) => setTimeout(r, wait * 1000));
  }
  throw new Error("Gave up after " + tries + " tries");
}
```

```python
import time, requests

def call(method, url, tries=5, **kw):
    for i in range(tries):
        res = requests.request(method, url, **kw)
        if res.status_code != 429 and res.status_code < 500:
            return res
        wait = float(res.headers.get("Retry-After", 2 ** i))
        time.sleep(wait)
    raise RuntimeError(f"Gave up after {tries} tries")
```
