Errors & rate limits
Failures are explicit and typed: every error returns a structured envelope rather than a silent fallback.
Error envelope
Every error response shares one shape:
{
"error": "VALIDATION_ERROR",
"message": "window.to must be after window.from",
"issues": [ … ], // present for VALIDATION_ERROR, the raw Zod issue array
"detail": { /* endpoint-specific context, e.g. maxKm, openDriftEvents */ }
}issues and detail are both optional and independent: issues is reserved for Zod validation failures; detail carries whatever free-form context a specific error needs (never both nested inside each other).
Status codes
| Status | Code | Meaning |
|---|---|---|
| 422 | VALIDATION_ERROR | Payload failed Zod validation. issues[] (top-level, not nested under detail) lists each failing path. |
| 401 | UNAUTHORIZED | API key absent, malformed, or hash mismatch. Rotate the key from the tenant portal. |
| 402 / 403 | PAYMENT_REQUIRED / PLAN_UPGRADE_REQUIRED | Endpoint needs a higher plan (e.g. underwriting, historical years, ensemble scoring, projections). Which of the two codes, and which status, depends on the endpoint. The LLM endpoints (intelligence, decision, counterfactual) are NOT in this bucket; they're open on every plan, gated only on whether your own Anthropic key is set (see below). |
| 403 | FORBIDDEN | Authenticated but missing the required scope (or tenant suspended). |
| 422 | LLM_KEY_INVALID | PUT /v1/tenant/llm-key rejected: Anthropic didn't accept the supplied key. Check it's active and has model access. |
| 429 | RATE_LIMITED | Daily safety cap or monthly quota exhausted for the tenant. Resets at 00:00 UTC (daily) or the 1st of the month (monthly). |
| 429 | LLM_BUDGET_EXCEEDED | Per-tenant monthly Anthropic-token spend guard exhausted. Resets the 1st of the month UTC; see /docs/concepts/llm-byok. |
| 503 | SERVICE_UNAVAILABLE | A required dependency isn't wired on this deployment (e.g. historical provider, spatial resolver): a deployment issue, not a caller error. |
| 503 | INTELLIGENCE_UNAVAILABLE | No Anthropic key configured for this tenant on an LLM route. Set one via PUT /v1/tenant/llm-key on any plan. |
Retries
Retry 429 and 503 with exponential backoff, or, on a 429, honour the Retry-After header (seconds) the API returns. Every response also carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (omitted on unlimited plans) so you can self-throttle before you hit the cap. 4xx other than 429 are deterministic: fix the request rather than retrying. The SDK throws GoableApiError (carrying status + code) for non-2xx and GoableNetworkError for transport failures.
Quotas and rate limits
On paid tiers the monthly quota is the billing line; overage is metered via Stripe once you exceed it. On Free (a hard cap) there is no overage: requests return 429 once the monthly quota is exhausted, resetting on the 1st of the month (UTC). The daily column is a per-tenant DDoS safety cap; it resets at 00:00 UTC and only kicks in for runaway loops.
| Plan | Monthly quota | Daily safety cap |
|---|---|---|
| Free | 1,000 / month | 50 / day |
| Starter | 50,000 / month | 5,000 / day |
| Pro | 500,000 / month | 50,000 / day |
| Scale | Unlimited | Unlimited |