Limits.
Two rate limiters, a few fixed ceilings, and your package's allowances. Every answer tells you where you stand, so a program can pace itself instead of finding a limit by hitting it.
The account's rate
- Calls are counted per account, across all its keys and projects:
api_per_mina minute, with bursts up toapi_burst. Both are inlimitsonGET /v1/auth; the test account on these pages has 600 a minute and a burst of 1200. - It is a token bucket, not a fixed minute: the bucket holds
api_burstcalls and refills continuously atapi_per_min. A quiet program can spend a burst at once; a busy one gets the steady rate. - A call counts once its key is known — including one refused afterwards for its scope or a missing dataset. A call refused for its key is not counted, and neither are
GET /v1andGET /v1/openapi.json, which need no key.
The headers
On every answer to a keyed call — not only on the refusal:
x-ratelimit-limit: 1200 the bucket depth (api_burst)
x-ratelimit-remaining: 1199 calls left in it
x-ratelimit-reset: 1 seconds until it is full again
x-ratelimit-policy: 600;w=60;burst=1200 the rate, the window, the depth
Limitis the bucket depth, not the per-minute rate:Remainingcounts down from it. The rate is inPolicy.- Pace from
Remaining: when it gets low, slow toapi_per_min.
When it is spent
retry-after: 1
{
"error": {
"code": "RATE_LIMITED",
"message": "Your account is limited to 600 API calls a minute, with bursts to 1200. Wait 1s.",
"limit": 600,
"burst": 1200,
"retry_after": 1
}
}
- Wait
Retry-Afterseconds, then carry on. It is the time for one call to come back, so a program that keeps calling at its full speed will meet it again: slow toapi_per_min. - Not run here because it means spending the test account's whole burst.
- If the counter is unavailable on our side the API lets calls through rather than refusing them; the web server's limit still applies.
The web server's limit
In front of the API, the web server allows 100 requests a second from one address, with a burst of 40, to protect the machine. Past it the answer is a 503 with an HTML page, not JSON and not the account's 429. Slow down and retry with a backoff. A program inside its account's rate never meets it.
Sizes and pages
| What | Limit | Over it |
|---|---|---|
| A request body | 10 MB (10,485,760 bytes) — every endpoint, files included | 413 TOO_LARGE, as JSON with limit_bytes — the same answer whether the web server in front or the API refuses it |
| A file's bytes | the 10 MB body: 10 MB sent as it is, about 7.5 MB as base64 | 413 TOO_LARGE |
| Records in one write | 10,000 (max_records_per_call) | 400 TOO_MANY |
| A page of records or changes | 1–1000, default 100 | clamped, not refused |
| A page of files | 1–1000, default 200 | clamped |
| A page of webhook deliveries | 1–200, default 50; 50 with include=payload | cut to the cap |
| A record key, a partition value | 190 characters | cut to 190, not refused |
| A setting's value | 64 KB as stored | 400 INVALID_VALUE |
A webhook's data (from the app) | 64 KiB | refused, and the app is told |
Storage
Records and files share one allowance with your app's code. A write is checked against three ceilings, innermost first, before anything is written, and each has its own word because each is a different conversation:
| Ceiling | Word | Who moves it |
|---|---|---|
the dataset's own storage_limit_bytes (retention never) | 403 DATASET_FULL | you, on the dataset |
| the project's storage limit, set in the portal | 403 PROJECT_FULL | the account owner, in the portal |
the account's storage_mb | 403 STORAGE_FULL | the account owner, by changing package |
Each carries limit_bytes, used_bytes and adding_bytes. What a PUT replaces counts as freed, so republishing a catalogue of the same size always fits. A dataset with retention_mode days or space makes its own room on each write and says so in pruned. See retention.
Webhooks
webhooks— whether the package includes them (403 NO_WEBHOOKSon create, change and test; reads still work).webhook_endpoints— how many the account may have, across all projects (403 LIMIT_REACHED); 0 is no limit.webhook_per_min— deliveries a minute ArdaForm makes for the account; an app's call over it is refused on the device, and a Test over it is429 RATE_LIMITED.- The delivery log keeps 500 deliveries or seven days per webhook.