Skip to main content
The guided questionnaire endpoints let your application ask a Hi Doctor consultation questionnaire one question at a time, while Hi Doctor applies the branching, validation and progress rules for you. Every call needs a patient bearer token and works on the same saved draft as PATCH .../progress/, so a patient can start in your application and finish in the Hi Doctor web app. Last reviewed: 2026-11-04 Hi Doctor operates across the whole European Union: residents of all 27 EU member states can use the service, and every consultation is reviewed by an EU-licensed doctor. Get the slug from the categories list (see questionnaire endpoints). All four endpoints return Cache-Control: no-store; do not cache their responses.

How does the guided loop work?

1

Read the current item

GET current/ returns question (a descriptor, or null when nothing is pending), complete, status, progress and an opaque revision. Show question.title, help, options and constraints.
2

Send the answer

POST answer/ with question_key, the value and expected_revision. The response is the next item, in the same shape as current, with a new revision.
3

Let the patient go back

POST back/ returns the previous answered item with its saved_answer. To change it, send the new value to answer/.
4

Review

When complete is true, GET review/ shows every applicable answer with a readable answer_label. Check ready_to_submit and missing_required_keys.
5

Submit

Read GET progress/ and post its progress.data to POST submit/ as {"data": [...]}. The guided endpoints never submit on their own.
The questionnaire is answered by the patient. Your application shows the questions and passes on what the patient enters. Never fill in clinical answers from inference, defaults or another person’s data.

How do you read the current item?

A shortened response:
reusable_prefill can offer an answer the patient gave in an earlier consultation. Show it as a suggestion and send it only after the patient confirms it; until then the question is not answered. current never creates or changes saved progress.

Send an answer

Use the value shape that matches the question: values is accepted as an alias of value; send only one of them.
A full answer to a question must leave all of that question’s required fields populated, including any follow-ups the answer opens. Otherwise the request returns 400 with code: "required" and nothing is saved. Other questions can stay unanswered.

Skip an optional question

Optional questions stay in order. Once the required answers are valid, complete can be true while question still holds an unanswered optional item. Offer it, or move past it explicitly:
Send the literal true and no value. Only optional questions can be skipped. A skip counts as handled in progress and is accepted by submit. Answering the question later replaces the skip. Skipping an optional question removes its answer and does not open its follow-ups.

Answer one grid item or follow-up

Grids are served one row at a time, and follow-ups an answer opens appear as their own items. Their descriptors carry the address to answer them:
  • A grid item has values_key. Send it with the value under that key:
  • A follow-up has option_input_key (conditional fields use the form __cf_<fieldName>) and parent_question_title. Send the value in option_inputs:
Including the selector asks for that one item only, and its value is required. Field maps merge with the values already saved.

Send a batch

Send several answers in one request with answers:
The batch is atomic: if any entry is invalid, nothing is saved. Applicability is checked against the final merged result, whatever the order of the entries, so a batch cannot answer a question that another entry in the same batch makes inapplicable. Do not mix answers with a single-answer question_key.

Revisions and conflicts

revision is a token for the content of the draft. Send it back as expected_revision. If another write changed the draft in between (another tab, the web app, or a parallel request), the answer is rejected:
The response is HTTP 409 and nothing was saved. Read current/ or review/ again, show the patient the up-to-date question, and send the answer with the new revision. Saving data that has not changed keeps the same revision, so repeating an identical answer is harmless. back/ never changes the revision.
answer/ does not take an Idempotency-Key. expected_revision is what makes a retry safe here. See safe retries for the endpoints that do.

What happens when an answer closes a branch?

Changing an answer can make other questions no longer apply. Their answers, and any answers that depend on them, are removed from the draft. The response lists what was removed:
dropped_question_keys names whole answers that were removed. dropped_option_inputs names follow-up values removed while their parent answer was kept. Tell the patient when an answer they gave has been cleared.

How does the patient go back?

POST back/ with an empty JSON object returns the last answered item before the first pending one, or the final answered item when everything is handled. Send question_key to pick an answered question, and add values_key or option_input_key to pick one grid row or follow-up.
Selecting a question that has no answer, or that no longer applies, returns 400 with code: "unanswered_question".

How do you review and submit?

GET review/ returns one row in answers per applicable question, in order, with saved_answer, a localized answer_label and items for grid rows and follow-ups. Each item has an answered flag and its values_key or option_input_key, so you can send the exact payload for anything still pending.
  • missing_required_keys names parent questions that still need an answer. A question can have a saved selection and still be listed because one of its items is pending.
  • errors reports invalid saved values, including values written earlier through PATCH .../progress/, and upload ownership problems.
  • ready_to_submit uses the same checks as submit. Submit can still apply separate renewal and subscription rules.
To submit, read GET progress/ and post its progress.data unchanged:
Submission returns 201 and sends the questionnaire for review by an EU-licensed doctor. POST submit/ accepts an Idempotency-Key, so a timed-out submission can be retried without creating a second one. Visiting the guided endpoints after a submission starts a fresh draft.
Clinical eligibility is decided by the questionnaire rules and the reviewing doctor. An answer can be rejected with code: "clinical_ineligibility". Show the message to the patient and do not retry with changed answers.

Which languages are supported?

All four endpoints accept locale=en, locale=es or locale=zh; any other value falls back to English. On POST requests the locale can also be sent in the body; the query parameter wins. Otherwise the patient’s account language is used, with English as the fallback. The locale changes titles, labels and help text only. Question keys and option values stay the same. The Hi Doctor service is available in eight languages; these guided endpoints serve the three listed here.

Renewals

For a renewal, send the same renewal_origin, renewal_changed, treatment_id, dosage and, where it applies, consultation_id on every guided call and on submit. GET requests take them as query parameters and POST requests in the JSON body. Dosage eligibility is still checked at submit.

Errors

Validation errors return 400 with a code and a message for each field. They never echo the patient’s values:
A body that is not JSON returns 415. An unknown category slug returns 400 with a detail message, and a category that is not enabled for the brand returns 403 with code: "category_not_enabled_for_brand". A stale expected_revision returns 409, as described above. See errors and recovery for 401 and 429 handling.

Frequently asked questions

Do I need to implement the questionnaire branching myself?

No. The guided endpoints return the next question that applies and remove answers that stop applying. Your application only shows each question and sends the patient’s answer.

Can a patient start in my app and finish on hi-doctor.ai?

Yes. The guided endpoints and the Hi Doctor web app work on the same saved draft, so the patient can continue in either place.

What does a 409 stale revision response mean?

Another write changed the draft after you read it, so nothing was saved. Read the current item again, show the patient the up-to-date question and send the answer with the new revision.

Is it safe to retry an answer after a timeout?

Yes, when you send the same expected revision. A repeated identical answer keeps the same revision, and a stale one is rejected without saving.

Can my application fill in answers for the patient?

No. The questionnaire is answered by the patient. Never fill in clinical answers from inference, defaults or another person’s data.

What happens if an answer rules out the consultation?

The answer is rejected with the clinical ineligibility code. Show the message to the patient and do not retry with changed answers; eligibility is a clinical outcome.

Does the guided flow submit the questionnaire?

No. The guided endpoints never submit. When the review shows the draft is ready, post the saved progress data to the submit endpoint.

Next steps