Errors
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
Section titled “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
Section titled “Status codes”400 — bad_request
Section titled “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
Section titled “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
Section titled “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
Section titled “404 — not_found”Resource doesn’t exist — wrong endpoint or ID not found.
{ "error": { "code": "not_found", "message": "Node 999999999999 not found." }}408 — timeout
Section titled “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
Section titled “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 RequestsRetry-After: 60X-RateLimit-Limit: 10X-RateLimit-Remaining: 0429 — daily_limit_exceeded
Section titled “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
Section titled “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
Section titled “503 — unavailable”Temporarily unavailable (deployment or maintenance). Retry with backoff.
{ "error": { "code": "unavailable", "message": "Service temporarily unavailable." }}Retry strategy
Section titled “Retry strategy”Only retry these status codes:
- 429 — Rate limited. Wait for
Retry-Afterseconds, 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
Section titled “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 youconst delay = Math.min(500 * Math.pow(2, attempt) + Math.random() * 500, 30000)SDKs handle retries
Section titled “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/503const plaza = new Plaza({ apiKey: 'pk_live_abc123' })
// Override if you wantconst plaza = new Plaza({ apiKey: 'pk_live_abc123', maxRetries: 5,})SDKs respect Retry-After headers on 429s automatically.