Skip to main content
Every error, on every endpoint, uses the same envelope:
{
  "error": "invalid_request",
  "message": "2 members are missing fields required for enrollment.",
  "details": [
    { "index": 3, "field": "email", "message": "email is required for enrollment" },
    { "index": 9, "field": "lastName", "message": "lastName is required for enrollment" }
  ]
}
  • error: a stable, machine-readable code. Branch on this.
  • message: human-readable; wording may change, so never parse it.
  • details: present on invalid_request, with one entry per failing field and an index when the payload is an array (census rows, enrollment member checks).

Error codes

StatusCodeMeaningWhat to do
400invalid_requestValidation failed; see details.Fix the listed fields and retry.
401unauthorizedMissing, malformed, or revoked API key.Check the Authorization: Bearer header and the key’s status.
403live_mode_disabledLive key used before live mode is enabled for your account.Stay on psk_test_ until the go-live checklist is complete.
403forbiddenThe key may not access this resource.Verify you’re using the right partner’s key.
404not_foundNo such resource in this mode: test keys can’t see live resources, and account/members 404 until enrollment.Check the ID, the key’s mode, and the group’s lifecycle stage.
409conflictDuplicate state: an enrolled group already exists for this domain, or the group already has an active enrollment.Treat as “already done”; fetch the existing resource and reconcile.
410quote_expiredThe quote has passed its expiresAt (rate-card driven; default 30 days).Create a new quote (deterministic; an unchanged census re-prices identically) and retry.
422census_requiredQuote requested with no quotable census.PUT /census first; each member needs zip + dob | age.
429rate_limitedRate limit exceeded. Retry-After header included.Back off per Rate limits.
500server_errorFailure on our side. The request was not applied.Retry with the same Idempotency-Key.
503not_configuredThe API’s backing store is unavailable; we fail closed rather than partially.Retry with backoff; contact your partner engineer if it persists.

Handling patterns that hold up

  • Branch on error, log message. Codes are contractual; messages aren’t.
  • 409 is usually success. Both conflict cases mean “the thing you wanted already exists”; fetch it and continue rather than surfacing an error.
  • Retry 500/503 with the same Idempotency-Key on POST/PUT. Replays within 24 hours are safe by construction; see Rate limits & idempotency.
  • Don’t blanket-retry 4xx. Other than 429 and the 410 re-quote flow, 4xx errors need a changed request, not a repeated one.