OverviewAPI ReferenceResources

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.


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.

PlanRequests per hour
Starter100
Professional500
Enterprise2,000

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

Successful responses carry three headers.

HeaderTypeMeaning
X-RateLimit-LimitintegerRequests allowed per hour on your plan
X-RateLimit-RemainingintegerRequests left this hour
X-RateLimit-ResetUnix timestampWhen 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.

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

Other 429 responses

ResponseCauseWhat 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_exceededYour AI credits are used up for the month or the day, or the spending cap is reached. See Tier Access.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.

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 tell you when a call is ready instead of polling GET /conversations.

Was this page helpful?