Errors

Every non-2xx response follows the same envelope (derived from RFC 7807):

{
  "error": {
    "code": "INVALID_DATE_RANGE",
    "message": "from_date must be earlier than to_date",
    "details": { "from_date": "2026-04-10", "to_date": "2026-04-01" }
  }
}
  • code is stable and machine-readable. Changing a code is a breaking change.
  • message is human-readable. It may be improved at any time; do not pattern-match on it.
  • details is optional and context-specific.

Error codes

HTTPCodeMeaning
400INVALID_DATEDate string not YYYY-MM-DD.
400INVALID_DATE_RANGEfrom_date > to_date, or demographics range > 90 days.
400INVALID_CURSORPagination cursor cannot be decoded.
400REQUIRED_PARAMETERA required query param is missing or malformed.
401UNAUTHORIZEDAPI key missing or invalid.
403FORBIDDENKey is valid but lacks the permission for this endpoint.
404NOT_FOUNDResource doesn't exist, or it's outside your key's company scope.
429RATE_LIMITEDSee Rate Limiting.
500INTERNAL_ERRORUnexpected server error (uncaught exception). Retrying may succeed if transient.
503UPSTREAM_UNAVAILABLEA dependency (metrics, demographics pipeline) is down. Safe to retry.

404 vs 403

We return 404 NOT_FOUND for any resource outside your company scope — even if the underlying record exists. 403 FORBIDDEN is only for permission mismatches (e.g. hitting /demographics with a key that only has partner:assets:read). This prevents cross-tenant existence probing.

Retrying

CodeRetry?
INVALID_*, REQUIRED_PARAMETER, NOT_FOUND, FORBIDDEN, UNAUTHORIZEDNo. Fix the request.
RATE_LIMITEDYes, after retry_after_seconds.
INTERNAL_ERROR, UPSTREAM_UNAVAILABLEYes, with exponential backoff — start at 1s, double to 60s, cap at ~5 attempts.