# Rate Limits

Each plan allows a number of requests per hour. How they are counted, which headers show the count, and how to handle a 429.

Source: https://docs.itsconvo.com/rate-limits

API Base URL: https://www.itsconvo.com/api/v1

Each account can make a set number of requests per clock hour (UTC). All its API keys share the count, and it resets on the hour.

| Plan | Requests per hour |
|------|:-----------------:|
| Starter | 100 |
| Professional | 500 |
| Enterprise | 2,000 |

Every request with a valid key counts, including requests that end in an error. Requests from the local [MCP server](/mcp) count too. The hosted MCP server and webhook deliveries don't.

Successful responses carry three headers.

| Header | Type | Meaning |
|--------|------|---------|
| `X-RateLimit-Limit` | integer | Requests allowed per hour on your plan |
| `X-RateLimit-Remaining` | integer | Requests left this hour |
| `X-RateLimit-Reset` | Unix timestamp | When the count resets: the next full hour, in seconds |

Over the limit you get `429 rate_limited` with the same headers and `Retry-After`, the seconds until the next hour.

```json
{ "error": { "code": "rate_limited", "message": "Rate limit exceeded (100 requests per hour for starter plan)" } }
```

## Other 429 responses

| Response | Cause | What to do |
|----------|-------|------------|
| `429 rate_limited`, message `OpenAI rate limit exceeded. Please try again later.` | The AI model is busy. Only on the AI generation endpoints, without headers. | Wait a few seconds and retry |
| `429 ai_limit_exceeded` | Your AI credits are used up for the month or the day, or the spending cap is reached. See [Tier Access](/tiers). | Don't retry. Check `GET /user/profile`. |
| `429` with `{ "error": "Rate limit exceeded", "message": "…" }` | A request without an `Authorization` header. These are limited to 100 per 15 minutes per IP address. | Send your key |

## Handling a 429

Read `error.code` before you retry. Only `rate_limited` clears by waiting.

```javascript
const res = await fetch(url, { headers });
if (res.status === 429) {
  const { error } = await res.json();
  if (error?.code === "ai_limit_exceeded") throw new Error(error.message);
  const wait = Number(res.headers.get("Retry-After") ?? 5);
  await new Promise((r) => setTimeout(r, wait * 1000));
  // send the same request again
}
```

To use fewer requests, let [webhooks](/webhooks) tell you when a call is ready instead of polling `GET /conversations`.