# Limits Every limit the API applies, in one place, so a script can stay inside them instead of finding them in a `429`. The numbers on this page are generated from the API's own code at build time; they cannot drift from what it enforces. ## What each plan includes | | Free | Pro | Business | Enterprise | |---|---|---|---|---| | An assistant reads through the MCP server (Connect with InfraNest) | Yes | Yes | Yes | Yes | | API tokens: read | No | Yes | Yes | Yes | | API tokens: write | No | Yes | Yes | Yes | | API tokens per organization | 0 | 5 | 20 | Unlimited | | Requests per minute, per token | 300 | 300 | 300 | 300 | | Changes per minute, per token | 60 | 60 | 60 | 60 | | Changes per hour per hour, per token | 1000 | 1000 | 1000 | 1000 | These are the standard plans. An organization on a plan agreed separately may have other numbers; its own limits are under **Settings → Subscription** in the app. API tokens count across the organization's members. Your [sandbox](sandbox.md) takes test tokens on every plan. **Free** includes the read-only assistant: Claude or ChatGPT [connected with InfraNest](ai/claude-and-chatgpt.md) can read your account. Calling the API yourself, with a token, starts at **Pro**, for reads and writes alike. Writes also need API writes switched on for the organization ([`write_disabled`](errors.md#write_disabled)). ## Rate limits Each token has its own budget, counted per window: | Budget | Default | What counts | |---|---|---| | Requests | 300 per minute | Every request | | Changes | 60 per minute | Every `POST`, `PUT`, `PATCH` and `DELETE` (these also count as requests) | | Changes per hour | 1,000 per hour | Every `POST`, `PUT`, `PATCH` and `DELETE`, over a rolling hour | Every response to a token carries the budget that is closest to running out: ```http X-RateLimit-Limit: 60 X-RateLimit-Remaining: 57 X-RateLimit-Reset: 1793030460 ``` `X-RateLimit-Reset` is a Unix time. Over a budget, the API answers `429` with the code [`rate_limited`](errors.md#rate_limited), the `Retry-After` header and `retry_after` in the body (seconds), and `limit_key` naming the budget: ```json { "code": "rate_limited", "message": "This token made more than 60 changes in a minute.", "limit_key": "api_writes_per_minute", "limit": 60, "retry_after": 12, "retryable": true } ``` Wait that long and carry on. A dry run counts as a change. The app's own sessions are not counted here. ## Everything else | Limit | Value | |---|---| | Token lifetime | 90 days unless you choose another: 30, 90, 180, 365 days. Never "no expiry". | | Page size of a list | 25 by default, at most 200 (`per_page`). A larger number is lowered to 200. A few lists differ and say so on their reference entry. | | `Idempotency-Key` | 1 to 255 visible ASCII characters. A successful answer is kept for 24 hours. | | Request body | JSON. Up to 8 MB: PHP's default limit, which the API does not change. | | One MCP answer | At most 80,000 characters; a longer answer is cut off with a note on how to narrow it. | | OAuth access token | 60 minutes, renewed with the refresh token. | | OAuth refresh token | 30 days, used once: each refresh returns a new one. An assistant not used for that long has to be connected again. | | OAuth authorization code | 10 minutes, used once. | | Write spike warning | The organization's owners are told once a day when a token makes more than 10 times its usual daily writes (at least 200; 1,000 for a token less than 3 days old). Nothing is blocked. | Lists are described in [Pagination and filtering](pagination.md); keys and retries in [Retries and dry runs](retries-and-dry-runs.md); tokens in [Tokens and scopes](tokens-and-scopes.md).