PrecisionDocs

Errors & Rate Limits — Developer Docs

The error envelope, common error types, per-route limits, and the 202-then-poll pattern.

What does an error response look like?

Errors return a structured envelope in detail:

{
  "detail": {
    "type": "bootstrap_not_ready",
    "message": "Project knowledge base is still building.",
    "recovery_action": "Poll GET /v1/projects/{project_id} until chat_ready is true, then retry."
  }
}

recovery_action is optional. For backward compatibility, 402 and 503 responses also carry a legacy top-level error key — it is deprecated; parse detail.

The per-route rate limiter is the one exception to the detail envelope: its 429 carries type: "rate_limited", message, and retry_after_seconds at the top level, plus a Retry-After header. It is always transient - wait the named seconds and retry the same call.

Common error types:

TypeStatusMeaning
not_found404Unknown resource, or a project outside your organization
insufficient_scope403Key lacks the scope for this endpoint
bootstrap_not_ready409Knowledge base still building — poll and retry
zoning_verification_required409Parcels need zoning confirmation before agent work
idempotency_key_reused409Same Idempotency-Key sent with a different payload
idempotency_in_progress409A request with this Idempotency-Key is still running — retry
concurrency_limit_exceeded429Too many concurrent agent turns for this key (limit 2) - retry_after_seconds in the body and a Retry-After header
insufficient_credits402Organization wallet is empty
api_key_credit_cap_exceeded402This key hit its daily or monthly credit cap
async_turns_not_available501wait: false is not supported yet — use sync turns
search_unavailable503Search backend temporarily unavailable — retry with backoff

What are the rate limits?

Limits are per API key. Exceeding one returns 429 with a Retry-After header and a typed body naming the wait (type: "rate_limited" plus retry_after_seconds) - wait and retry the same call. The MCP client puts the wait in the error text as "Retry after Ns".

RouteLimit
POST /v1/projects8/min
POST /v1/plan-check20/min
POST .../sources, POST .../gis-sources10/min
POST /v1/uploads/initiate, POST /v1/uploads/{job_id}/finalize30/min
GET /v1/projects, GET /v1/projects/{id}60/min
PATCH .../parcels/{i}/zoning30/min
GET .../site-knowledge60/min
POST .../messages2/min (concurrency 2)
GET .../messages, GET .../messages/{turn_id}60/min
POST .../search30/min
POST .../summaries5/min
POST .../gis-exports10/min
POST .../maps10/min
POST /v1/parcels/resolve20/min
POST /v1/parcels/preview10/min
GET .../site-plan, GET .../design-criteria, GET .../yield-scenario60/min
POST .../site-plan-exports10/min
GET .../gis-exports/{artifact_id}30/min
POST .../reports5/min
GET .../reports, GET .../reports/{job_id}, GET .../artifacts60/min
GET .../artifacts/{artifact_id}30/min
GET /v1/wallet30/min

The 202-then-poll pattern: long-running work (project creation, report generation) returns 202 immediately. Poll the corresponding read endpoint every 5–15 seconds until the resource is terminal — never spin faster than the read limits.

Other API topics