Rate limits
Mandatum limits how fast a single key, and a single client address, can send requests. The limits protect the service for everyone. They leave plenty of room for an integration that runs one request at a time.
The limits #
| Tier | Limit | Counted by | Window |
|---|---|---|---|
| Normal | 100 requests | Each key, and separately each client IP | 60 seconds |
| Authentication failure | 5 failed attempts | The first 16 characters of the presented key, and the client IP | 60 seconds |
A request counts against the normal tier only after it authenticates, so a key that is revoked or mistyped never spends the normal budget. The authentication-failure tier limits guessing. Five failures in a minute from one address is a sign of a broken integration or an attack, and a developer who mistypes a key a few times will not reach it.
Requests from one client IP count against that IP's budget for every key. A shared office or a CI runner that calls with several keys shares one IP budget, so spread the load across time if you hit it.
What happens when you hit a limit #
The response is 429:
{
"error": "Too Many Requests"
}The general 429 body carries no code, and it does not send a Retry-After header, so the safe rule is to wait at least 60 seconds before retrying, and to back off exponentially if the retry also returns 429.
Workflow runs have their own limit. POST /api/v1/skills/run returns 429 with "code": "too_many_requests" and a Retry-After header giving the seconds to wait when too many runs start in a minute, for the user or the workspace. Honour that header. The SDKs do this automatically; see REST API.
Requests refused with 429 do not produce usage rows, and they do not produce a verified citation. Nothing is billed for a refused request.
Staying under the limit #
- Batch citation checks. One
POST /api/v1/citations/verifycall can carry up to 50 citations, each up to 512 characters. Fifty citations in one call costs one request from the limit. - Use the webhook for long workflows instead of polling
GET /api/v1/runs/{id}. See Webhooks and runs. - Issue a gap report once, not on every view. Identical content is reused and not billed. See Usage and units.
- Keep the results of searches your application repeats, rather than running the same search on every page view.
Storage of the counters #
The counters are kept in Redis when the deployment has it configured, so they are shared across every server instance. Without Redis, each instance counts on its own. Operators set this; clients do not need to do anything different.
Connected-app registration #
Dynamic client registration for connected apps (POST /api/oauth/register) is limited separately, per client address. It does not use your key's budget.