XUND
Guides

The question-answer loop

The state machine your integration must implement: the two answer shapes and the six question types, with how each is answered and advanced.

The loop

Once a check is initialized, your code repeats two calls until the check is over: GET /v1/chatbot/question returns the last unanswered question, you render it to the patient, and POST /v1/chatbot/answer submits their response — always for the last asked question only; earlier questions are corrected through the endpoints in Changing answers and recovering state. How exactly a question is rendered and answered depends on its type, which is the subject of this guide. The loop ends when the check is finished — the report has been fetched, or POST /v1/chatbot/answer responds with "checkStatus": "FINISHED" (the no-diagnosis path); The report covers what still works after that. For the concept-level view of the whole flow — initialization, the stages a check moves through, overview, report — see API Concept; for a runnable end-to-end script, see Your first check.

Two answer shapes exist, both POST /v1/chatbot/answer bodies:

// answer with a value (TEXT, NUMBER) or a selected option id (SINGLE_SELECT, EXTENDING)
{ "questionId": "6bcd3297-3c66-47c2-af3e-1fc8688be628", "answer": { "value": "1980" } }
{ "questionId": "e38f994b-6464-4c49-8b11-28687031d46d", "answer": { "id": "ebf2b5b3-1d42-40ec-bba0-6a43f9da5b5a" } }
// skip answer: a body without `answer`
{ "questionId": "183d2cd6-567f-416b-befb-065500cbaf57" }

Only one of answer.value / answer.id may be sent at a time. Whether a question may be skipped is indicated by its isSkippable flag.

Question types

The type field defines the question's basic behavior — there are six values:

typeHas options?Your UI rendersHow to answerHow the check advances
TEXTnoa free-text input; validate locally with answerValidatorRegexanswer.value with the entered textone answer (or skip, if skippable)
NUMBERnoa numeric input; enforce detailedTypeData.numberConstraints (min/max, either may be null), show unitText/placeholderTextanswer.value with the number as a stringone answer (or skip, if skippable)
SINGLE_SELECTyesthe options.values list, pick oneanswer.id with the chosen option's idone answer (or skip, if skippable) — the most frequent type
INFOnoa skippable progress/interstitial noticecannot carry an answer — see belowskip answer only
EXTENDINGyes, and the list growsa multi-select listone answer.id per POST, then re-request the question — see belowfinish the selection with a skip answer
FUNCTION—the related function's screen (overview or report)cannot be answered via POST /v1/chatbot/answer at all — see belowcomplete the related function

Option items always carry an id — whatever else your UI keys on (code, from/to ranges), the id is what you send back. text on questions is localized HTML.

INFO: advance by skipping

INFO questions are skippable progress/interstitial notices, not disclaimers — in practice their detailedType is PROGRESS, telling the patient where the check stands. They cannot be answered — sending an answer object is rejected — but they still must be passed: send a skip answer ({ "questionId": "..." }) to move on to the next question. Render them, let the patient acknowledge, then skip.

Actual disclaimers — the legal disclaimer, the backup-diagnosis, overheating, and no-diagnosis notices — do not arrive as INFO questions: they are SINGLE_SELECT questions with detailedType: "DISCLAIMER" (or NO_DIAGNOSIS) carrying an acknowledge option, so the generic single-select fallback renders them correctly; see Advanced question UI.

EXTENDING: select, re-request, repeat, finish with skip

EXTENDING questions (e.g. detailedType: "SYMPTOM_SUGGESTION" — "Which other symptoms are you experiencing?") let the patient select any number of options, and the option list extends with new relevant items after each selection:

  1. Render options.values as a multi-select list.
  2. When the patient selects an option, POST an answer with that option's id.
  3. Re-request the question with GET /v1/chatbot/question — the same question comes back with its option list expanded with new items, and previously selected items marked isSelected: true.
  4. Repeat 2–3 for as long as the patient keeps selecting.
  5. Finish with a skip answer. This is required for the check to move on: it confirms the selected options, or — if nothing was selected — skips the question.

To let the patient deselect an option, use DELETE /v1/chatbot/answer (see Changing earlier answers). For SYMPTOM_SUGGESTION questions, detailedTypeData.sendAnswerButtonText provides the localized label for the finish button — its value changes as selections accumulate (from a "nothing to add" wording to an "add the selected symptoms" wording), so re-render it after every re-request.

FUNCTION: use the function's endpoints instead of answering

A FUNCTION question appears when a dedicated function — the overview or the report — must be used, and GET /v1/chatbot/question keeps returning it until that function is completed (or the check is finished). It cannot be answered through POST /v1/chatbot/answer; the question's detailedType tells you which flow applies:

detailedTypeHow to complete it
OVERVIEWfetch GET /v1/chatbot/overview (mandatory), then confirm with POST /v1/chatbot/overview/confirm
SYMPTOM_CHECK_REPORT / ILLNESS_CHECK_REPORTfetch the report — GET /v1/chatbot/report or /report/pdf — this ends the check

The overview and The report cover both functions in depth.

Last updated on

On this page