# Rate limits

> Windows slide. Over a limit you get 429 and how many seconds to wait.

Source: https://taseli.co.il/en/developers/rate-limits

| Limit | Per | Counts |
| --- | --- | --- |
| 60 a minute | Key | API requests |
| 600 an hour | Key | API requests |
| 30 an hour | Key | Webhook creates, deletes and tests |
| 5,000 a day | Workspace | Every key and app, API and MCP together |
| 1,500 a minute | IP address | Any request with a bearer token, before the key is read |

The API's per-key windows are its own: a busy integration doesn't use up an AI conversation on the same key.

## Over a limit

Response 429:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests from this key. Try again in 42 seconds."
  }
}
```

`Retry-After` holds the seconds. Wait that long. There are no headers for what's left: Taseli counts on the server and tells you when to stop.

```js
async function get(url, tries = 3) {
  const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.TASELI_KEY}` } });
  if (res.status !== 429 || tries === 0) return res;
  const seconds = Number(res.headers.get("retry-after") ?? 60);
  await new Promise((done) => setTimeout(done, seconds * 1000));
  return get(url, tries - 1);
}
```

## Staying under

- Ad accounts sync once a day, so metrics don't move between syncs. `lastSyncAt` on an account says when the last one ran. Pull once a day, after it.
- Use webhooks for proposals and changes instead of polling.
