--- title: Errors | Plaza Docs description: Error response format, status codes, and retry strategies for the Plaza API. --- Plaza returns a JSON error body with an HTTP status code in the 4xx or 5xx range. ## Error format ``` { "error": { "code": "rate_limited", "message": "Rate limit exceeded. Retry after 60 seconds.", "details": { "limit": 10, "window_seconds": 60, "retry_after": 60 } } } ``` `code` is a stable, machine-readable string. `message` is a human-readable explanation that may change — don’t parse it. `details` is an optional object with structured metadata about the error — present on rate limit, daily limit, and payment errors. ## Status codes ### 400 — bad\_request Malformed request — missing required parameters, invalid geometry, bad filter syntax, etc. Fix your request; retrying won’t help. ``` { "error": { "code": "bad_request", "message": "Invalid geometry: expected a GeoJSON geometry object." } } ``` ### 401 — unauthorized Missing or invalid API key. Common causes: typo, revoked key, or missing header. ``` { "error": { "code": "unauthorized", "message": "Invalid API key" } } ``` ### 402 — payment\_required Subscription inactive — billing failed (expired card, cancelled subscription, etc). Reactivate from the billing dashboard. Free tier accounts get `429 daily_limit_exceeded` instead. ``` { "error": { "code": "payment_required", "message": "Your subscription is inactive.", "details": { "billing_url": "https://plaza.fyi/dashboard/billing" } } } ``` ### 404 — not\_found Resource doesn’t exist — wrong endpoint or ID not found. ``` { "error": { "code": "not_found", "message": "Node 999999999999 not found." } } ``` ### 408 — timeout Query took too long. Narrow your search area, add more specific tag filters, or paginate. ``` { "error": { "code": "timeout", "message": "Query exceeded 30s timeout. Try a smaller geometry or more specific filters." } } ``` Don’t retry the same query — it’ll time out again. Reduce scope. ### 429 — rate\_limited Per-minute rate limit exceeded. The `Retry-After` header tells you how long to wait. ``` { "error": { "code": "rate_limited", "message": "Rate limit exceeded. Retry after 60 seconds.", "details": { "limit": 10, "window_seconds": 60, "retry_after": 60 } } } ``` ``` HTTP/1.1 429 Too Many Requests Retry-After: 60 X-RateLimit-Limit: 10 X-RateLimit-Remaining: 0 ``` ### 429 — daily\_limit\_exceeded Free tier only. Daily allocation exhausted (500 standard or 10 premium requests). Resets at midnight UTC. ``` { "error": { "code": "daily_limit_exceeded", "message": "Daily limit of 500 standard requests exceeded. Resets at midnight UTC.", "details": { "limit": 500, "endpoint_type": "standard", "reset_at": "2026-03-20T00:00:00Z", "upgrade_url": "https://plaza.fyi/dashboard/billing" } } } ``` Upgrade to a Pro plan or wait for the daily reset. ### 500 — internal\_error Server-side error. Retry with backoff. If it persists, contact support. ``` { "error": { "code": "internal_error", "message": "An unexpected error occurred." } } ``` ### 503 — unavailable Temporarily unavailable (deployment or maintenance). Retry with backoff. ``` { "error": { "code": "unavailable", "message": "Service temporarily unavailable." } } ``` ## Retry strategy Only retry these status codes: - **429** — Rate limited. Wait for `Retry-After` seconds, then retry. - **500** — Server error. Retry with exponential backoff. - **503** — Unavailable. Retry with exponential backoff. Everything else (400, 401, 402, 404, 408) is a permanent failure. Retrying won’t help. `429 daily_limit_exceeded` is also a permanent failure until the daily reset at midnight UTC. Check `details.reset_at` instead of retrying. ### Exponential backoff with jitter For 500 and 503 errors, use exponential backoff with random jitter to avoid thundering herds: ``` delay = min(base * 2^attempt + random(0, base), max_delay) ``` A reasonable starting point: base of 500ms, max delay of 30 seconds, 3 attempts max. ``` // Pseudocode — the SDKs handle this for you const delay = Math.min(500 * Math.pow(2, attempt) + Math.random() * 500, 30000) ``` ### SDKs handle retries The TypeScript, Python, and Go SDKs handle retries with backoff and jitter out of the box. Only needed if you’re hitting the API directly. ``` // Retries are on by default — 3 attempts for 429/500/503 const plaza = new Plaza({ apiKey: 'pk_live_abc123' }) // Override if you want const plaza = new Plaza({ apiKey: 'pk_live_abc123', maxRetries: 5, }) ``` SDKs respect `Retry-After` headers on 429s automatically.