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

# Rate Limits

> Understand Datagrid API rate limits, response headers, and best practices for handling 429 responses

The Datagrid API enforces rate limits to protect the platform from abuse and ensure fair usage across all consumers.

## Default rate limit

The default rate limit is **200 requests per 60-second sliding window**, but individual endpoints may enforce their own limits. Check the `X-RateLimit-Limit` response header to see the effective limit for any given endpoint.

The limit is scoped per **teamspace**, **endpoint path**, and **HTTP method**. For example, `POST /v1/converse` and `GET /v1/agents` maintain independent rate limit windows within the same teamspace.

## Response headers

Every Datagrid API response includes rate limit headers so you can monitor your usage proactively:

| Header | Description | Example |
| - | - | - |
| `X-RateLimit-Limit` | Maximum requests allowed in the current window | `200` |
| `X-RateLimit-Remaining` | Requests remaining in the current window | `195` |
| `X-RateLimit-Reset` | Unix epoch second when the current window resets | `1741275120` |
| `Retry-After` | Seconds until the window resets (present when `X-RateLimit-Remaining` is `0`, including on `429` responses) | `30` |

## 429 Too Many Requests

When the rate limit is exceeded, the API returns a `429` status code with the following body:

```json theme={null}
{
  "status_code": 429,
  "statusCode": 429,
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded",
  "mitigation": "Implement exponential backoff and retry with delays",
  "retryable": true,
  "details": {
    "reason": "Rate limit exceeded. Please retry after the current window resets."
  }
}
```

> [!NOTE]
>
> `statusCode` is deprecated and will be removed in a future version. Use `status_code` instead.

The response also includes the `Retry-After` header indicating how many seconds to wait before retrying.

## Batch prediction rate limits

Batch prediction endpoints also use `429 Too Many Requests`, but they return RFC 9457 problem details (`application/problem+json`) instead of the legacy JSON shape above.

```json theme={null}
{
  "type": "https://api.datagrid.com/errors/rate_limit_exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "Too many batch prediction requests are already in progress for this teamspace."
}
```

Batch prediction `429` responses may also include:

| Header | Description |
| - | - |
| `X-RateLimit-Limit` | The numeric limit for the rule that rejected the request. |
| `X-RateLimit-Remaining` | Remaining capacity for the matched rule, usually `0` on `429`. |
| `X-RateLimit-Reset` | Unix epoch second when capacity is expected to reset, when applicable. |
| `RateLimit-Policy` | The batch admission-control rule that rejected the request. |
| `RateLimit` | Current limit state for the matched policy. |
| `Retry-After` | Seconds to wait before retrying. |

Batch create requests can be rejected by organization concurrency, enqueued-item, create-rate, or temporary global-capacity policies. Treat these responses as retryable and honor `Retry-After` before submitting more batch work.

## Credit caps

Account admins can set a daily and a monthly credit cap in Control Tower. Caps apply to the whole account, so usage from every teamspace and every client (API, app, and integrations) counts toward them.

When a cap is configured, endpoints that check credits before they run report how many credits are left under it. The headers are also on streaming responses (`stream: true`) and on the error returned when a cap is reached (`402`, or `403` problem details for batch predictions). These endpoints are:

* `POST /v1/converse` and `POST /v1/beta/converse`
* `GET /v1/search`, `POST /v1/search/ai`, and `GET /v1/search/tree`
* `POST /v1/knowledge`, `POST /v1/knowledge/connect`, and `POST /v1/knowledge/{knowledge_id}/reindex`
* `POST /v1/files`
* `POST /v1/batch-predictions`
* `POST /v1/data-views`
* `POST /v1/user-memories`
* `POST /v1/skills/generate`
* `POST /v1/beta/rewrite`
* `POST /v1/voice`

| Header | Description | Example |
| - | - | - |
| `X-Daily-Credit-Cap-Remaining` | Credits left before the daily cap is reached, rounded up | `600` |
| `X-Monthly-Credit-Cap-Remaining` | Credits left before the monthly cap is reached, rounded up | `15000` |

A header is omitted when its cap isn't configured. `0` means the cap has been reached:

* **Daily cap:** advisory. Requests are not blocked, so use the header to slow down or pause your own traffic.
* **Monthly cap:** credit-consuming requests return `402 Credit limit exceeded` (`403` for batch predictions) until the next calendar month.

> [!NOTE]
>
> Usage is measured when the request starts, so a single long-running request can take the account past a cap.

## Best practices

> [accordion] SDK automatic retries
>
> The official [Python](https://github.com/DatagridAI/datagrid-python) and [TypeScript/JavaScript](https://github.com/DatagridAI/datagrid-node) SDKs automatically retry `429` responses up to 2 times with exponential backoff. You can configure this via the `maxRetries` option:
>
> ```python Python theme={null}
> from datagrid_ai import Datagrid
>
> client = Datagrid(max_retries=5)  # default is 2; set to 0 to disable
> ```
>
> ```typescript TypeScript theme={null}
> import Datagrid from 'datagrid-ai';
>
> const client = new Datagrid({ maxRetries: 5 }); // default is 2; set to 0 to disable
> ```
>
> If you are using the SDK, you typically do not need to implement your own retry logic.

> [accordion] Use exponential backoff
>
> If you are calling the API directly (without the SDK), implement retry logic yourself. When you receive a `429`, wait for the number of seconds specified in the `Retry-After` header before retrying. If `Retry-After` is not available, use exponential backoff starting at 1 second, doubling with each retry up to a maximum of 60 seconds.
>
> ```python Python theme={null}
> import time
> import httpx
>
> def request_with_backoff(client, **kwargs):
>     max_retries = 5
>     delay = 1
>
>     for attempt in range(max_retries):
>         response = client.post(**kwargs)
>         if response.status_code != 429:
>             return response
>
>         retry_after = response.headers.get("Retry-After")
>         wait = int(retry_after) if retry_after else delay
>         time.sleep(wait)
>         delay = min(delay * 2, 60)
>
>     return response
> ```
>
> ```typescript TypeScript theme={null}
> async function requestWithBackoff(
>   fn: () => Promise<Response>,
>   maxRetries = 5
> ): Promise<Response> {
>   let delay = 1000;
>
>   for (let attempt = 0; attempt < maxRetries; attempt++) {
>     const response = await fn();
>     if (response.status !== 429) return response;
>
>     const retryAfter = response.headers.get("Retry-After");
>     const wait = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay;
>     await new Promise((resolve) => setTimeout(resolve, wait));
>     delay = Math.min(delay * 2, 60_000);
>   }
>
>   return fn();
> }
> ```

> [accordion] Monitor X-RateLimit-Remaining
>
> Check the `X-RateLimit-Remaining` header on every response. If it drops below a threshold (e.g., 10% of the limit), slow down your request rate before hitting a `429`.

> [accordion] Distribute requests across endpoints
>
> Since rate limits are scoped per endpoint path and HTTP method, you can make concurrent requests to different endpoints without them counting against the same window.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.