Rate limits
Per-project quotas, what each plan allows, and which endpoints are exempt.
Limits are counted per project, not per key or per IP — all traffic from one project shares one budget. Every window is 60 seconds.
Route classes
Each endpoint is assigned a cost class, and each class has its own quota:
Music is deliberately exempt. What bounds it is the concurrent-player ceiling instead, because a music bot routinely issues far more than 80 commands a minute while still being a well-behaved caller.
Plan limits
The aggregate row is deliberately lower than the sum of the classes above it.
Without it, a client could spend its whole cheap quota and never notice it had
no canvas budget left.
A 0 in the puppeteer row is a feature gate, not “unlimited”. The free
plan does not include screenshots or Minecraft renders at all, and asking for
one answers 403, not 429. See upgrade required.
Reading your remaining budget
Every metered response carries the current state:
X-RateLimit-Limit is the limit for the class that request hit. Retry-After
appears only when you are being held back.
Two responses have no headers at all: GET /v1/status, because the public path
skips the limiter, and every player-class request, because Music has no quota.
When you hit a limit
A 429 uses the standard error envelope. The message tells you
which budget ran out:
Respect Retry-After rather than retrying on a fixed timer — the limiter uses a
smooth window, so a client that backs off recovers immediately while one that
retries on a schedule keeps the debt alive.
Upgrade required
Asking for a feature your plan does not include returns 403, not 429, and
carries your plan in the headers so you can see which one you are on:
Change your plan from aegi.run.
Burst behaviour
Quotas are enforced with GCRA, which allows a burst equal to the per-minute limit but then smooths the recovery. A rejected request does not push the window forward — otherwise a client in a retry loop would build a penalty box and stall legitimate traffic for minutes.
If the rate limiter’s own storage is unavailable, requests are allowed through rather than failed. A limiter outage should never take the API down with it.