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

# Rate Limits

> Xobito enforces per-token request limits to protect workspace capacity.

Rate limits are enforced **per API token**, not per IP address or per workspace. Every token gets its own counter.

## Default limit

**60 requests per minute, per token.**

Your workspace administrator can change this in workspace settings (`rate_limit_max` for the ceiling, `rate_limit_decay` for the window in minutes). Contact your admin if you need a higher limit.

## 429 response

When you exceed the limit, Xobito returns HTTP `429 Too Many Requests` with this body:

```json theme={null}
{
  "message": "Too many requests",
  "retry_after": 45
}
```

| Field         | Meaning                                                   |
| ------------- | --------------------------------------------------------- |
| `message`     | Always `"Too many requests"`.                             |
| `retry_after` | Seconds to wait before the next request will be accepted. |

<Note>
  Unlike other endpoints, the 429 response does not include a `status` field. Treat any response with HTTP status `429` as rate-limited.
</Note>

## Handling 429s

Wait the number of seconds in `retry_after`, then retry the same request. A simple loop:

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function call(url, options) {
    for (let attempt = 0; attempt < 5; attempt++) {
      const res = await fetch(url, options);
      if (res.status !== 429) return res;
      const { retry_after } = await res.json();
      await new Promise((r) => setTimeout(r, (retry_after || 1) * 1000));
    }
    throw new Error("Rate limited after 5 retries");
  }
  ```

  ```python Python theme={null}
  import time, requests

  def call(url, **kwargs):
      for _ in range(5):
          r = requests.request(url=url, **kwargs)
          if r.status_code != 429:
              return r
          time.sleep(r.json().get("retry_after", 1))
      raise RuntimeError("Rate limited after 5 retries")
  ```

  ```php PHP theme={null}
  function call(string $url, array $options, int $max = 5) {
      for ($i = 0; $i < $max; $i++) {
          $ch = curl_init($url);
          curl_setopt_array($ch, $options);
          $body = curl_exec($ch);
          $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
          curl_close($ch);
          if ($status !== 429) return [$status, $body];
          $retry = json_decode($body, true)['retry_after'] ?? 1;
          sleep($retry);
      }
      throw new RuntimeException('Rate limited after retries');
  }
  ```
</CodeGroup>

## Quotas

Separately from the per-minute limit, tokens can be configured with a **monthly quota** (total calls per calendar month). When the quota is exhausted, requests are rejected until the quota resets at the start of the next month. Monthly quota is optional and configured per token in **Settings → API Management**.

## Best practices

<Tip>Use one token per integration, so one noisy service does not starve others.</Tip>
<Tip>Back off with `retry_after` instead of guessing. Xobito returns the exact wait time.</Tip>
<Tip>Batch related work where possible — e.g. create contacts in parallel up to your limit, not in a tight loop.</Tip>
<Tip>Monitor `429` response counts in your own observability stack.</Tip>
