Rate Limits

Understand and handle API rate limits

Fair usage

Rate limits keep the platform fair and stable for everyone. Every plan includes generous limits, and clients should handle 429s with automatic retries.

Plan limits

PlanPriceRequests/moTokens/moSeats
Free
$0100200K1
Starter
$15/mo1,0001.5M1
Pro
$49/mo8,00012M1
Team
$149/mo40,00060M5
Enterprise
CustomCustomCustomUnlimited
Free plan — no credit card required

Start immediately with 100 requests and 200K tokens per month. All 60+ models are available on every paid plan. Free/Starter/Pro are individual plans; Team/Enterprise are separate workspace plans for teams, not an upgrade path from Pro.

Two limits, not one

| Limit | Scope | What happens | |---|---|---| | Monthly quota (table above) | Per user / per team owner's plan | 429 with code: rate_limit_exceeded. No Retry-After — it clears at the start of the next month. | | Short-term burst | Per client IP, not per plan | POST /v1/ai/*: 20 requests / minute. Every other endpoint: 100 / minute. 429 with a Retry-After header. |

A retry loop that only waits for Retry-After will spin against the monthly quota. Check the status body: if code is rate_limit_exceeded and there is no Retry-After, you are out of monthly quota — back off long, or upgrade.

Rate limit headers

Burst-limited responses carry the standard headers:

HTTP
HTTP/1.1 200 OK
RateLimit-Limit: 100
RateLimit-Remaining: 95
RateLimit-Reset: 42          # seconds until the window resets
Retry-After: 42              # only on a 429

Successful chat requests also return your monthly-quota position:

HTTP
X-Monthly-Requests-Used: 1240
X-Requests-Limit: 8000
X-Requests-Remaining: 6760
X-Monthly-Tokens-Used: 402113
X-Tokens-Limit: 12000000

Handling rate limits

Bounded backoff — honours Retry-After, adds jitter
async function makeRequestWithRetry(url, options, maxRetries = 4) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);
    if (response.status !== 429 && response.status < 500) return response;
    if (attempt === maxRetries) return response; // give up — let the caller see it

    const retryAfter = Number(response.headers.get('Retry-After'));
    const waitMs = Number.isFinite(retryAfter) && retryAfter > 0
      ? retryAfter * 1000                                   // burst limit — server told us
      : Math.min(2 ** attempt * 1000, 30000) + Math.random() * 1000; // quota / 5xx — backoff + jitter

    console.log(`Retrying in ${Math.round(waitMs)}ms (attempt ${attempt + 1})`);
    await new Promise(r => setTimeout(r, waitMs));
  }
}

// Usage
const response = await makeRequestWithRetry(
  `${BASE_URL}/v1/chat/completions`,
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      model: 'gemini-2.5-flash',
      messages: [{ role: 'user', content: 'Hello!' }]
    })
  }
);
Best practices

Implement exponential backoff for retries · monitor rate limit headers proactively · cache responses when possible · batch requests where you can · contact support for higher limits