Rate limits
How many requests the Coritan API accepts, the tighter limits on sign-in and some actions, and how to handle a 429 response.
The Coritan API limits how many requests it takes from one address, how many failed sign-ins it accepts, and how often you can repeat an action that costs a lot to carry out. A request over any limit answers 429 Too Many Requests, and the Retry-After header says how many seconds to wait.
Requests from one address
Section titled Requests from one address| Limit | What it counts | Answer |
|---|---|---|
| 2,400 requests a minute | Every API request from one IP address in the last 60 seconds | 429 with {"detail": "Rate limit exceeded"}. Retry-After is the number of seconds until the oldest of those requests is a minute old. |
| 200 requests a second, in bursts of up to 400 | Every request from one IP address, counted by the proxy in front of the API | 429 with {"error":"Too many requests"} and Retry-After: 1. |
| 128 connections | Open connections from one IP address to the proxy | The proxy closes a new connection without an answer. |
The proxy's limits are its defaults, and Coritan can change them. When the proxy refuses 8 requests in a row from one address, it blocks that address for 5 minutes. While the block lasts, every request answers 429 and every new connection is closed, so do not retry at once after a 429.
Sign-in attempts
Section titled Sign-in attemptsOnly failures count towards these limits: an answer of 401 or 403. A sign-in that works costs nothing.
| Limit | Routes | Answer |
|---|---|---|
| 40 failed attempts a minute, from one IP address, on each route | POST /auth/login, POST /auth/register and POST /auth/refresh; on an organization, POST /orgs/{org_slug}/auth/login, /auth/register and /auth/forgot-password, and POST /orgs/{org_slug}/staff/auth/login and /staff/auth/forgot-password |
429 with {"detail": "Too many authentication attempts. Please try again later."} and Retry-After: 60. |
POST /auth/forgot-password always answers 200, so it has a budget that counts every request instead: 10 in 15 minutes from one IP address, and 3 in 15 minutes for one email address. Checking a two-factor code has one too, as the next table shows.
Actions with their own budget
Section titled Actions with their own budgetThese actions start work that takes time or resources on Coritan's side, so each has a budget of its own on top of the limits above. The budget counts your requests for one server, instance or route, or for your whole account where the table says so.
| Action | Routes | Budget |
|---|---|---|
container.power |
POST /client/servers/{uuid}/power |
24 a minute |
container.wake |
POST /client/servers/{uuid}/wake |
48 a minute |
container.backup |
POST /client/servers/{uuid}/backups |
8 in 5 minutes |
container.backup_restore |
POST /client/servers/{uuid}/backups/{backup_uuid}/restore |
8 in 5 minutes |
container.file_compress |
POST /client/servers/{uuid}/files/compress and /files/decompress |
24 a minute |
container.file_pull |
POST /client/servers/{uuid}/files/pull |
24 a minute |
container.import |
POST /client/servers/{uuid}/import/start and /import/test-connection |
12 in 5 minutes |
container.software |
The routes under /client/servers/{uuid}/software/ that install, change or update software |
8 in 10 minutes |
container.database |
POST /client/servers/{uuid}/databases |
24 a minute |
vps.power |
POST /client/vps/{uuid}/power |
24 a minute |
vps.rebuild |
POST /client/vps/{uuid}/rebuild |
8 in 10 minutes |
vps.backup |
POST /client/vps/{uuid}/backups |
8 in 5 minutes |
vps.backup_restore |
POST /client/vps/{uuid}/backups/{backup_id}/restore |
8 in 5 minutes |
custom_domain.link |
POST /client/external-servers/{service_id}/custom-domain and POST /gameproxy/routes/{route_id}/custom-domain |
12 an hour |
custom_domain.verify |
The same two routes with /verify added |
12 an hour |
external_server.update |
PATCH /client/external-servers/{service_id} |
30 in 5 minutes |
external_server.probe |
POST /client/external-servers/{service_id}/test |
20 a minute, for your account |
platform_domains.availability |
GET /client/platform-domains/availability |
60 a minute, for your account |
platform_domains.claim |
POST /client/platform-domains/claims |
6 an hour, for your account |
crypto.deposit_check |
POST /billing/crypto/check |
12 a minute, for your account |
storefront.free_order |
POST /services/order for a plan that costs nothing |
12 in 10 minutes, for your account |
user.mfa_verify |
POST /auth/mfa/verify, /auth/mfa/enable, /auth/mfa/disable and /auth/mfa/recovery-codes together |
10 in 5 minutes, for your account |
apps.create |
POST /client/apps, and POST /orgs/{org_slug}/apps for an organization |
20 an hour, for the account or organization that will own the app |
apps.write |
Every request that changes an app under /client/apps/ or /orgs/{org_slug}/apps/: creating, changing or deleting it, its variables, domains, deployments and webhook secret |
120 an hour, for each person or API key |
apps.deploy |
POST .../{app_uuid}/deployments, POST .../{app_uuid}/redeploy and a rollback |
30 in 10 minutes, for each app |
apps.domain_verify |
POST .../{app_uuid}/domains/{hostname}/verify |
30 in 10 minutes, for each app |
The matching routes of an organization's customer portal, under /orgs/{org_slug}/portal/, have the same budgets for each customer. The staff console has budgets of its own on actions such as charges, refunds, credit and exports.
Over a budget, the action answers:
{
"detail": {
"error": "rate_limited",
"message": "Too many requests for this action. Please wait and try again.",
"action": "container.power",
"retry_after_seconds": 60
}
}
retry_after_seconds and the Retry-After header both give the length of the whole window. Waiting that long always frees the budget.
Apps answers the same way without action, and its message names what ran out, such as Too many deployments of this app. Wait a few minutes.
Organization API keys and the Store API
Section titled Organization API keys and the Store API- Organization API key
- Each key has its own limit, set when it is created: 4,000 requests in any 60 minutes by default. Over it, the Commerce API answers
429withAPI key rate limit exceededandRetry-After: 3600. Create organization API keys sets the limit. - Store API payments
- Starting a payment and completing a cart each allow 20 tries for one cart in 10 minutes, and 60 from one IP address for one store. Over either, the Store API answers
429with"error": "rate_limited", the messageToo many payment attempts for this cart. Try again in a few minutes.andRetry-After: 600.
SMTP Relay has sending limits of its own, which SMTP Relay sending limits describes.
Handle a 429
Section titled Handle a 429- Read
Retry-After, a whole number of seconds, and send nothing more to that route until it has passed. - When an answer has no
Retry-After, wait 1 second, then double the wait after each429up to a minute, with a random part added so that many clients do not retry at the same moment. - Never retry in a loop without a wait: 8 refusals in a row block your address for 5 minutes.
- Poll less often, and read a list once instead of one record at a time (Pagination and filtering).
- When you retry a payment or an order after a
429or a lost connection, send the sameIdempotency-Key, so that it happens only once (Idempotent requests).