> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minidesk.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limits

> 600 a minute per credential, with a 60 a second burst ceiling.

Limits are counted **per credential**, not per workspace. Two integrations
holding two tokens do not eat into each other's budget. That is the main reason
to issue a separate credential per system rather than sharing one.

| Window     | Limit        |
| ---------- | ------------ |
| Per minute | 600 requests |
| Per second | 60 requests  |

The per-second ceiling exists so one client cannot burn through the whole
minute's allowance in the first second and lock everyone else out for the
remaining fifty-nine.

## Headers

Every response carries your current standing, not just the ones that fail:

```http theme={null}
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 594
X-RateLimit-Reset: 1786000000
```

`X-RateLimit-Reset` is a Unix timestamp in seconds.

## When you go over

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 12
```

```json theme={null}
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests"
  }
}
```

`Retry-After` is in seconds and always rounded up, so waiting exactly that long
is enough. Rounding down would send you back a fraction early and earn you a
second `429`.

## Handling it

Wait for `Retry-After` rather than guessing at a backoff. The server already
knows when your window resets, and the header is that answer.

```js theme={null}
async function call(url, options, attempt = 0) {
  const response = await fetch(url, options);

  if (response.status !== 429 || attempt >= 5) return response;

  const wait = Number(response.headers.get("Retry-After") ?? 1);
  await new Promise((resolve) => setTimeout(resolve, wait * 1000));

  return call(url, options, attempt + 1);
}
```

<Tip>
  Watch `X-RateLimit-Remaining` on the responses you are already getting and
  slow down before you hit zero. It is cheaper than being throttled.
</Tip>

## The widget is limited differently

[The chat widget](/channels/chat-widget) has no credential, so it is limited
per origin and per visitor address instead. Anonymous placements are the abuse
surface, and they are metered accordingly.

## Rate limits are not quotas

A `429` says you are going too fast and will be fine shortly. A `402` says the
workspace has used its conversations for the period, and waiting will not help.
See [Quotas](/guides/quotas).
