Errors, Limits & Timeouts

Error format, HTTP status codes, rate limits, and recommended client timeouts

Error response format

All error responses carry an error string:

{
  "error": "Included or excluded answers must be provided"
}

Request validation failures (400) also include a validation_errors array:

{
  "error": "1 request validation error(s).",
  "validation_errors": ["age: Min[Age must be at least 18 years old]"]
}

Always log error and validation_errors — they are the actionable part. This text is technical and not meant for end users: your UI supplies its own copy for these states (e.g. the technical fault screen and the invalid-age message — see Copy your UI supplies).

HTTP status codes

StatusMeaningTypical causes / handling
200Success—
400Bad requestValidation failures: missing partner_id/secret; age outside 18–125; initial_query outside 3–500 chars; answer type doesn't match the current question; neither included nor excluded provided; choice ids missing from both lists, or not in the current question; excluded sent for an autocomplete question; report requested before report_possible; disallowed X-Language; analytics value too large. Fix the request — do not retry as-is.
401UnauthorizedBad partner credentials at login; an expired/invalid token elsewhere; or calling a medical endpoint with the non-upgraded token (Terms and conditions not accepted. — check the two-token flow). Mid-conversation this means the session is gone: re-login, re-accept terms, start a new assessment.
403ForbiddenInvalid/revoked API key or domain validation failure. Check credentials.
404Not foundGET /chat before any conversation exists; unknown article id.
429Too many requestsPartner rate limit exceeded (see below). Back off and retry.
5xxServer errorGET calls: retry with backoff. POST /chat and POST /step-back: don't resend — recover with GET /chat (see Retry semantics below); a 504 doesn't mean the answer was not applied. If persistent, contact support.

Rate limits (per partner)

Enforced at the gateway per API key:

LimitWhat it means
Sustained rateThe steady request rate your integration can send, averaged over time. Staying under this is what keeps you clear of 429s.
BurstShort spikes above the sustained rate that the gateway tolerates for a few seconds — headroom for moments like several users answering at once, not extra sustained capacity.
Daily quotaThe total number of requests allowed per day. Once exhausted, further requests are rejected until the quota resets.

Notes:

  • These are partner-wide, shared across all of your users — another reason the API must sit behind your own backend, where you can queue/throttle. The actual values are set in your contract — contact Healthily if you're unsure what yours are.
  • The chattiest endpoint is /symptom-search (per keystroke) — debounce it client-side (e.g. 300 ms) and require 2–3 characters before querying.
  • On 429, apply exponential backoff. Do not tight-loop retries.

Recommended client timeouts

Server-side processing budgets per endpoint — set your client timeouts a little above these:

EndpointServer budget
POST /login20 s
POST /initial, POST /chat, POST /step-back, GET /chat20 s
GET /report20 s
GET /symptom-search3 s
GET /articles, GET /article/{id}10 s
GET /terms, POST /terms5 s
POST /analytics, POST /analytics/feedback20 s

Typical latencies are far lower; the chat budget is generous because a single turn can involve NLU and diagnostic-engine calls.

Retry semantics — the important nuance

POST /chat is not idempotent: it advances the conversation. If a chat call times out or the connection drops, do not blindly resend it — the answer may already have been applied, and a resend would be validated against the next question (usually yielding a 400, but don't rely on that).

Safe recovery procedure: call GET /chat (read-only) and simply render the question it returns — it is the authoritative current state. If the timed-out answer was applied, you'll be showing the next question; if it wasn't, the user re-answers the same one. No client-side comparison or bookkeeping is needed.

GET endpoints and POST /analytics are safe to retry. POST /step-back has the same non-idempotent caveat as /chat (each call steps back one question).

Operational guidance

  • Token expiry: track expires_in from login and warn users on long pauses; an expired session cannot be resumed.
  • Sequential calls only per conversation: never issue concurrent POST /chat calls on one token.
  • Don't parse debug_messages or build logic on scenario values — both are diagnostic aids, not contract.
  • Monitor your quota: a full consultation is typically 10–25 requests (login, terms ×2, initial, 5–15 chat turns, report, plus searches/articles). Size your expected daily volume against the quota and request an increase if needed.

Did this page help you?