Errors, limits & versions
Problem Details
Every error is an RFC 9457 problem, application/problem+json:
{
"type": "https://www.k-stra.com/errors/insufficient_credits",
"title": "Insufficient credits",
"status": 402,
"detail": "The run was blocked before anything was charged.",
"error": "insufficient_credits",
"errorCode": "3f9a1c2b7d",
"instance": "/api/v1/actions/analysis.people_economy/execute",
"blockedBy": "organization_balance",
"credits": 2
}
type is stable per error code. error is the code (the same one the web app uses). errorCode correlates the request in our logs: quote it when you contact support.
detail is a sentence in English written for a person: show it to your user, log it, but do not parse it. Its wording can improve at any time without a new version; error and type are what your code should branch on.
Catalogue
| Status | error |
When |
|---|---|---|
| 400 | invalid_input |
the body is not a JSON object with the action's input |
| 400 | validation_error |
the input does not respect the action's rules; a required field left out is listed in missing and named in detail |
| 400 | quote_required |
a charged execution without quotedCredits |
| 400 | not_chargeable |
/quote called on a free action |
| 401 | not_authenticated |
no valid API key (WWW-Authenticate: Bearer) |
| 402 | insufficient_credits |
balance or a limit does not cover the run; nothing charged; see blockedBy |
| 403 | scope_required |
the key lacks the scope this route needs (run to spend, manage to write analyses, read their sharing and manage webhooks) |
| 403 | forbidden |
the action is not available to this key |
| 404 | unknown_action |
no action with that id in the public API |
| 404 | not_found |
the analysis, version, job, job result or webhook does not exist or is not yours to see |
| 404 | unknown_tool |
MCP only: no tool with that name (tools/list has the current ones) |
| 409 | quote_changed |
the quote no longer matches quotedCredits; nothing charged; quotedCredits carries the new value and declaredCredits the one you sent |
| 429 | rate_limited |
too many requests; wait Retry-After seconds |
| 503 | engine_unavailable |
the geographic engine is restarting; nothing charged; retry in a few seconds |
| 500 | internal_error |
our fault; errorCode identifies the request |
Limits
| Limit | Value |
|---|---|
| Requests per key (REST and MCP together) | 600 per minute |
| Charged executions per key (REST) | 60 per minute |
| Engine-heavy calls (isochrones, quotes, and charged executions, which quote again before they run) | 30 per minute per IP, 2 concurrent isochrones per IP |
| Continent | data is served for oceania (Australia) only; europa stays in the schemas but is refused with 400 validation_error ("Unknown continent") before anything is charged |
| Isochrone | 1 to 10 origins; 1 to 8 bands for analysis.isochrone, 1 to 6 in the analyses; up to 120 minutes or 30 km |
| Territory | up to 1,000,000 address poles for areas and drawn polygons, and also for catchments in real estate; analysis.people_economy on administrative areas has no limit, the whole country included; sector analyses up to 400,000 on any territory; 1 to 12 areas, 1 to 10 polygons with 5,000 vertices in all. Refused with 400 before anything is charged |
Store networks (network.coverage) |
2 to 500 stores plus up to 100 candidates, catchments up to 60 minutes, at most 50,000,000 address poles across all catchments (refused before charging) |
Coverage points (analysis.brand_coverage) |
up to 500 points (beyond, the first 500 are analysed and the result says so), catchments up to 30 minutes, same 50,000,000-pole ceiling |
| Request body | 8 MB |
| Active keys per user | 20 |
| Webhook endpoints per organization | 10 |
| Dataset storage | first 50 MB per organization free, then 2 credits a month every 100 MB; unpaid, the datasets are suspended and actions that read them are refused with 400 (see Credits) |
| Webhook delivery attempts | 4 (now, +1 min, +10 min, +1 h); an endpoint is disabled after 20 consecutive failures |
Versions and deprecation
The version in the specification (info.version) is the contract version. It grows on additive changes only. Nothing is removed from v1; a deprecated element would keep working and carry the Deprecation and Sunset headers for at least twelve months, with a line in the Changelog.