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
| Status | Meaning | Typical causes / handling |
|---|---|---|
200 | Success | — |
400 | Bad request | Validation 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. |
401 | Unauthorized | Bad 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. |
403 | Forbidden | Invalid/revoked API key or domain validation failure. Check credentials. |
404 | Not found | GET /chat before any conversation exists; unknown article id. |
429 | Too many requests | Partner rate limit exceeded (see below). Back off and retry. |
5xx | Server error | GET 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:
| Limit | What it means |
|---|---|
| Sustained rate | The steady request rate your integration can send, averaged over time. Staying under this is what keeps you clear of 429s. |
| Burst | Short 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 quota | The 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:
| Endpoint | Server budget |
|---|---|
POST /login | 20 s |
POST /initial, POST /chat, POST /step-back, GET /chat | 20 s |
GET /report | 20 s |
GET /symptom-search | 3 s |
GET /articles, GET /article/{id} | 10 s |
GET /terms, POST /terms | 5 s |
POST /analytics, POST /analytics/feedback | 20 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_infrom login and warn users on long pauses; an expired session cannot be resumed. - Sequential calls only per conversation: never issue concurrent
POST /chatcalls on one token. - Don't parse
debug_messagesor build logic onscenariovalues — 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.
Updated 3 days ago
