Errors, Limits & Timeouts
Error format, HTTP status codes, rate limits, and recommended client timeouts
Error response format
All error responses share one body shape:
{
"error": "BadRequest",
"message": "Included or excluded answers must be provided"
}Always log message — it is the actionable part.
HTTP status codes
| Status | Meaning | Typical causes / handling |
|---|---|---|
200 | Success | — |
204 | No content | e.g. logout |
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 not in the current 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, or an expired/invalid token elsewhere. Mid-conversation this means the session is gone: re-login, re-accept terms, start a new assessment. |
403 | Forbidden | Invalid/revoked API key, domain validation failure, or calling a medical endpoint with the non-upgraded token. Check credentials and the two-token flow. |
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 | Retry with backoff; if persistent, contact support. |
Rate limits (per partner)
Enforced at the gateway per API key:
| Limit | Default |
|---|---|
| Sustained rate | 2 requests/second |
| Burst | 10 requests/second |
| Daily quota | ~10,000 requests/day |
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. Actual values are per your contract; treat the above as defaults.
- 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 | 30 s |
POST /initial, POST /chat, POST /step-back, GET /chat | 30 s |
GET /report | 30 s |
GET /symptom-search | 3 s |
GET /articles, GET /article/{id} | 10 s |
GET /terms, POST /terms | 5 s |
POST /analytics, POST /analytics/feedback | 30 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) to fetch the authoritative current question. - Compare with what you last rendered:
- Same question → your answer was not applied; resend it.
- Different question → your answer was applied; render the new question and continue.
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.
