RateLimit-* headers, and a 429 response includes Retry-After so you know how long to wait before retrying.
Burst limit
120 requests / 60s across all endpoints. Smooths out spikes of traffic.
Generation quota
500 generations / rolling 30 days. Both
POST /diagrams/generate and POST /diagrams/{id}/edit count.The same limits apply to the MCP server: each tool call counts as a request to its endpoint, and generations made through it share the same monthly quota.
The two limits
120 requests / 60s
Applies to every request made for the account, with any of its keys or connected assistants, regardless of endpoint. When you exceed it you receive a
429 with code rate_limit_exceeded. The window is a rolling 60 seconds.500 generations / rolling 30 days
Applies to
POST /diagrams/generate and POST /diagrams/{id}/edit (both use scope generate and run an AI generation). Every request counts once against the quota, including requests refused with an error. When the quota is exhausted you receive a 429 with code quota_exceeded. The window is a rolling 30 days.Both limits are tracked per account. All API keys and connected AI assistants of your personal account share one set of counters, and all keys and assistants of an organization share another.
Response headers
Every API response carries the rate-limit headers, so you can read your remaining allowance without waiting for a429.
integer
The maximum number of requests allowed in the current window.
integer
The number of requests remaining in the current window.
integer
The number of seconds until the current window resets.
integer
Present only on
429 responses. The number of seconds to wait before retrying.Example: a normal response
Handling 429 responses
A429 Too Many Requests always has error.type of rate_limit_error. Inspect error.code to tell the two limits apart, then use the Retry-After header to decide how long to wait.
Example: a 429 burst response
Recommended strategy
1
Read the code
On a
429, branch on error.code. Treat rate_limit_exceeded as retryable and quota_exceeded as a hard stop for the current window.2
Honor Retry-After
Wait at least
Retry-After seconds (it is provided in seconds) before retrying. Never retry sooner.3
Add exponential backoff with jitter
For repeated
rate_limit_exceeded responses, increase the delay on each attempt (e.g. Retry-After, then 2x, 4x…) and add random jitter to avoid thundering-herd retries. Cap the number of attempts.4
Stop on quota_exceeded
Do not retry
quota_exceeded in a loop. Surface it to the operator and resume after the rolling window frees up capacity.Backoff example
FAQ
Do RateLimit-* headers appear on every response?
Do RateLimit-* headers appear on every response?
Yes.
RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset are returned on every API call. Retry-After is added only on 429 responses.Which calls count against the generation quota?
Which calls count against the generation quota?
POST /diagrams/generate and POST /diagrams/{id}/edit. Every request counts once, including requests refused with an error. Polling GET /generations/{id} does not count against the quota, but every request still counts against the 120/60s burst limit.Are the limits per key or per account?
Are the limits per key or per account?
Per account. Your personal account and each organization have their own burst and quota counters, shared by all of their API keys and connected AI assistants. Creating more keys does not raise the limits.
What's the difference between rate_limit_exceeded and quota_exceeded?
What's the difference between rate_limit_exceeded and quota_exceeded?
Both are
429 with error.type rate_limit_error. rate_limit_exceeded means you hit the short-term burst limit (120/60s) — retry after Retry-After seconds. quota_exceeded means you exhausted the 500-generations rolling 30-day quota — retrying immediately won’t help; wait for the window to free up or upgrade.