Skip to content

Errors

Every error response is JSON with a stable shape:

{
"error": {
"status": 401,
"code": "invalid_key",
"message": "API key is invalid or revoked."
},
"request_id": "req_abc"
}

Forward the request_id to support when contacting us — it lets us trace exactly which call failed.

Error catalogue

StatusCodeMeaning
400invalid_addressMissing or too-short address parameter.
400invalid_urlURL parameter missing or fails our URL validator.
400invalid_idListing id is malformed.
400invalid_filterA filter key is unknown or value is out of range.
400missing_fieldRequired field absent from request body.
401unauthenticatedNo Authorization header.
401invalid_keyAPI key not found or revoked.
403forbiddenAuthenticated, but lacks scope to access this resource.
404not_foundListing or job not found.
409conflictResource already exists (e.g. duplicate webhook URL).
422validation_failedBody fails JSON schema validation.
429rate_limitedRPM threshold exceeded for your plan.
429quota_exceededAccount is out of credits. Top up or wait for renewal.
500internal_errorUnhandled server-side error. We get paged.
502upstream_failureUpstream lookup failed. Retry-safe with exponential backoff.
504upstream_timeoutUpstream took too long. Retry-safe.

Retrying

  • 429 rate_limited — back off until your next minute and retry.
  • 429 quota_exceeded — do not retry. Top up or wait.
  • 5xx — retry with exponential backoff, capped at 60s.
import httpx, time
def call_with_retry(url, headers, retries=3):
for attempt in range(retries):
r = httpx.get(url, headers=headers, timeout=30)
if r.status_code < 500 and r.status_code != 429:
return r
if r.status_code == 429 and r.headers.get("retry-after"):
time.sleep(int(r.headers["retry-after"]))
else:
time.sleep(2 ** attempt)
return r

Next