Errors

Synthient returns conventional HTTP status codes and machine-readable JSON bodies for every failure.

HTTP error shape

Most error responses follow a small, consistent JSON envelope. Validation errors use a slightly richer body so you can show field-level messages.

Generic error

{ "detail": "Invalid API Key" }

Validation error

{
  "title": "Validation error",
  "errors": {
    "ip_address": ["must be a valid IP address"]
  }
}

The HTTP Content-Type is always application/json. Empty bodies should be treated as transient infrastructure errors and retried.

Status code reference

StatusMeaningWhat to do
400 Bad RequestInvalid input malformed IP, bad cursor, oversized batch.Fix the request before retrying. The body usually identifies the offending field.
401 UnauthorizedMissing or invalid x-api-key header.Verify the key is loaded from the environment and not truncated. See Authentication.
402 Payment RequiredLookup credit balance is exhausted.Add credits, upgrade your plan, or wait for lookup_quota.resets_in to elapse. See Rate Limits.
403 ForbiddenAPI key lacks the scope required for this endpoint.Check granted scopes via /account/me; reach out to support to add the missing one.
404 Not FoundSnapshot, domain, or other resource doesn't exist.Don't retry the resource is genuinely missing.
429 Too Many RequestsPer-key rate limit or concurrent-stream limit hit.Back off using the Retry-After header if present; otherwise exponential backoff with jitter. See Rate Limits.
500 Internal Server ErrorUnexpected server error.Retry with backoff. If the issue persists, contact support.
503 Service UnavailableStreaming or downstream backend temporarily down.Retry with exponential backoff and jitter.

Per-status examples

400 Bad Request

Returned when the request fails validation before any work is done. The body identifies the offending fields.

Malformed IP address

{
  "title": "Validation error",
  "errors": { "ip_address": ["must be a valid IP address"] }
}

Oversized batch

{
  "title": "Validation error",
  "errors": { "ips": ["must contain at most 1000 entries"] }
}

401 Unauthorized

The API key was missing or rejected. Check that the value is non-empty and that you're using the x-api-key header.

{ "detail": "Invalid API Key" }

402 Payment Required

You've spent your remaining lookup credits. Inspect lookup_quota.credits and lookup_quota.resets_in on /account/me to see when your balance resets.

{ "detail": "Quota exhausted" }

403 Forbidden

The key is valid but isn't scoped for the requested endpoint or feed. For example, calling /feeds/anonymizers/stream with a key that only has PROXY_FIREHOSE.

{ "detail": "Insufficient scope for this resource" }

404 Not Found

There is no parquet snapshot for the requested date, or the domain has never been observed.

{ "detail": "Snapshot not found" }

429 Too Many Requests

Returned when you exceed the per-key request rate or attempt to open more concurrent streams than your plan allows. Honour the Retry-After response header (seconds) when present.

{ "detail": "Too many concurrent streams" }

500 / 503 Server errors

A 500 indicates an unexpected fault on our side; a 503 indicates the streaming or downstream backend is briefly unavailable. Both are safe to retry use exponential backoff with jitter and cap the delay at 60 seconds.

{ "detail": "Internal Server Error" }

Recovery checklist

  1. Read the status code first. 4xx means your request needs to change; 5xx means ours does retry safely.
  2. Honour Retry-After on 429. When present, wait at least that many seconds.
  3. Use exponential backoff with jitter. Start at 1s, double up to a 60s cap, randomize ±25% so a flock of clients don't synchronize.
  4. Don't retry 400, 403, 404. They will not become success without a code change.
  5. Surface the detail body. Forward it to your logs it's the fastest way to diagnose unexpected failures.

Next steps