Rate Limits
How the limit is counted
Requests are counted per endpoint, per organization. Each endpoint has its own budget, so heavy use of one endpoint does not slow another.
Two things follow from "per organization", and neither is obvious:
- Requests made on behalf of a child organization count against the parent. If you use the
on-behalf-ofheader, every child shares one budget per endpoint. A parent with hundreds of children has the same allowance as a parent with one. - Extra API keys do not buy extra throughput. An organization can hold several active keys, but they all draw on the same budget.
Reading your current allowance
Every response carries your allowance for that endpoint:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 38| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window |
X-RateLimit-Remaining | Requests still available |
X-RateLimit-Reset | Seconds until the window resets |
Read X-RateLimit-Limit rather than hardcoding a number. The limit may change, and a client that reads the header keeps working when it does.
When you exceed the limit
A request over the limit returns 429 with a RateLimitExceededError body:
{
"errorInstanceId": "a3b033fc-0000-0000-0000-000000000000",
"name": "RateLimitExceededError",
"message": "Too many requests. Please retry shortly.",
"params": {
"retryAfterSeconds": 54
}
}The response also carries a standard Retry-After header with the same value, plus X-RateLimit-Limit, X-RateLimit-Remaining: 0 and X-RateLimit-Reset.
Wait retryAfterSeconds before retrying. Retrying sooner consumes budget you do not have and delays your recovery.
Avoiding the limit
Use webhooks instead of polling. Most rate limiting comes from polling for state that Mural already pushes to you. Subscribing to the event you are polling for removes the requests entirely and tells you sooner. See Webhooks.
Spread scheduled work. A job that runs on the hour concentrates every request into one window. Spreading the same work across the hour keeps you inside the limit without doing less.
Back off on 429, do not retry immediately. Honour Retry-After. A retry loop with no backoff turns one rejection into a sustained one.
Updated about 2 hours ago