Rate limits
Requests are limited so that one client cannot crowd out the others. A request over the limit is answered
HTTP 429
Retry-After: <seconds>with code: "rate_limited" in the body. Wait that long and send it again. The web app does this by itself: a change that hits a limit waits and is sent again, and is not lost.
The limits
Per minute. "By address" means per client address.
The API (:3009)
| What | Limit |
|---|---|
| Every request, by address | 3000 |
| Password sign-in for one account, by address | 10 |
| Password sign-ins over all accounts, by address | 60 |
| A signed-in person's changes | 1200 |
Narrower limits apply to a few things that cost more or send something out: adding people (which can send mail), making API keys, uploads, chat messages and new workspaces.
The MCP server (:8811)
| What | Limit |
|---|---|
| Every request, by address | 6000 |
| By API key | 300 |
| Requests with a key the server does not know, by address | 20, then nothing from that address is looked at until some come back |
GraphQL mutations go through the MCP server, so they count against the key's 300. GraphQL answers a limit with the error code RATE_LIMITED.
Webhooks (:8080)
| What | Limit |
|---|---|
| Every delivery, by address | 1200 |
| By connector | 600 |
| Deliveries to a connector nobody listens at, by address | 30 |
| Deliveries no trigger accepted, by address | 30 |
For whoever runs the server
- Behind a proxy, set
CK_CLIENT_IP_HEADERto the header the proxy puts the client's address in. Without it, everybody behind the proxy shares one address and one allowance. CK_RATE_LIMIT=offswitches limiting off.- Counts are kept in memory per process: two instances of a service each allow the full limit, and a restart starts the counts again.