Skip to navigation

Rate limits

Per-project quotas, what each plan allows, and which endpoints are exempt.

View as Markdown

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:

ClassEndpointsCost
cheapLookups and cached reads — status, jobs, Bible, holidays, Roblox, Minecraft info and textures, binary encode/decode, language listsLow
fetchCalls that hit an upstream service — translate, detect, roleplay GIFsMedium
canvasImage filters and overlaysHigh
puppeteerWebsite screenshots, Minecraft rendersHighest
playerThe whole Music APIUnmetered

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

freestandardadvancedscale
cheap / min6040012006000
fetch / min151204002000
canvas / min10602001000
puppeteer / min—2060300
Aggregate / min8055017008500
Concurrent players51535100

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-Plan: standard
X-RateLimit-Class: fetch
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118

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:

{
"error": {
"code": "rate_limited",
"message": "This project is over the limit for fetch: 120 per minute."
},
"requestId": "0f8fad5b-d9cb-469f-a165-70867728950e"
}
MessageMeaning
...over the limit for {class}: {n} per minute.That one class is exhausted
...over its total request limit. Try again shortly.The aggregate budget is exhausted

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:

{
"error": {
"code": "forbidden",
"message": "puppeteer is not part of the free plan. Upgrade to use it."
},
"requestId": "0f8fad5b-d9cb-469f-a165-70867728950e"
}
X-RateLimit-Plan: free

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.