Documentation
Platform API
Build your solution
Navigating Question Flows

Navigating question flows

Basic flow

The diagram below shows the process of going through a survey:

  1. Step 1. Fetch current question.
  2. Step 2. If answer_type is list, fetch possible answers from meta.source_list_url.
  3. Step 3. Provide a user answer to the current question.
  4. Step 4. API returns status code 204 if the survey is completed. If the status code is 200, the response will contain the next question and you should go back to step 2.

Survey not found

Survey completed

Endpoints

To fetch the current question and give an answer, use the endpoints below.

Current question

To download the current question, make a GET request to /api/mgp/v1/surveys/{survey_id}/questions/current.

cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/current" \
  -X "GET"

Response

Response includes the question object. For more information, see the “Question object” section.

Example:

JSON
{
  "id": "visit_reason",
  "index": 0,
  "question": {
    "text": "What is the main reason for your visit?"
  },
  "answer_type": "multiple_choice",
  "meta": {
    "answers": [
      {
        "id": "symptoms",
        "label": "I have worrying symptoms"
      },
      {
        "id": "test-results",
        "label": "I want to discuss the test results"
      },
      {
        "id": "extend-prescription",
        "label": "I want to extend my prescription"
      },
      {
        "id": "follow-up",
        "label": "I have a follow-up visit"
      },
      {
        "id": "other",
        "label": "Other"
      }
    ],
    "has_rationale": false
  }
}

Give your answer

To answer the current question, send a POST request to /api/mgp/v1/surveys/{survey_id}/questions/current.

cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/current" \
  -X "POST" \
  -H "Content-Type: application/json" \
  -d '{
    "answer": [
      {
        "id": "symptoms"
      }
    ]
  }'

Request parameters in body

answer (required)

The transmitted value depends on the answer_type field in the question object. For more information, see the “Answer types” section.

Responses

HTTP status code: 200

The response was accepted. It also returns the object of the next question.

HTTP status code: 204

The response was accepted. No more questions. Survey is completed.

HTTP status code: 409

The survey has been closed. It is not possible to answer a completed survey.

Fetch previous question

If you need to fetch the previous question, call the GET method on /api/mgp/v1/surveys/{survey_id}/questions/{question_index}. The index param is the sequence number of the question in the survey.

cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/3" \
  -X "GET"

Answering previous questions

To answer a previous question, call the PUT method on /api/mgp/v1/surveys/{survey_id}/questions/{question_index}. The index param is the sequence number of the question in the survey. The questions depend on the answers given.

If you update a previous question, the answers to the following questions will be reset.

cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/1" \
  -X "PUT" \
  -H "Content-Type: application/json" \
  -d '{
    "answer": {"id": "female"}
  }'

Responses

HTTP status code: 200

The response was accepted. It also returns the object of the next question.

HTTP status code: 204

The response was accepted. No more questions. Survey is completed.

HTTP status code: 409

The survey has been closed. It is not possible to answer a completed survey.

List answers

To fetch all of the answers given in a survey, send a GET request to /api/mgp/v1/surveys/{survey_id}/questions. The response will include a paginated list of question objects with user answers. You can limit the elements on a page using the limit parameter:

cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions" \
  -X "GET" 

Request parameters in query

limit (number, optional)

Maximum limit of elements per page. Default value is 10, maximum value is 50.

cursor (number, optional)

Page number.

Example response

JSON
{
  "self": "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions?cursor=0",
  "first": "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions?cursor=0",
  "last": "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions?cursor=0",
  "items": [
    {
      "id": "visit_reason",
      "index": 0,
      "user_answer": {
        "answer": [
          {
            "id": "symptoms"
          }
        ]
      }
    },
    {
      "id": "sex",
      "index": 1,
      "user_answer": {
        "answer": {
          "id": "female"
        }
      }
    }
  ]
}

Answering the Plan Survey

To answer the Plan Survey (similar to the Intent Survey but after the finished interview), send a POST request to /api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/intent_after.

A value can be filled in for the form_of_contact field if kind_of_care is set to either primary or specialist. If kind_of_care is set to anything other than primary or specialist, status code 422 - Unprocessable entity will be returned.

The following values are possible for the kind_of_care field:

  • doing_nothing
  • self-care
  • primary
  • specialist
  • allied
  • urgent
  • emergency
  • ambulance
  • unknown

The following values are possible for the form_of_contact field:

  • in_person
  • teleconsultation
  • helpline
  • application
  • unknown
cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/intent_after" \
  -X "POST" \
  -H "Content-Type: application/json" \
  -d '{
    "kind_of_care": {"id": "specialist"},
    "form_of_contact": {"id": "application"}
  }'

Responses

HTTP status code: 200

The response was accepted. No further processing is needed.

HTTP status code: 422

Request was unprocessable. It could be due to:

  • A forbidden combination of the kind_of_care / form_of_contact fields, showing the error message: Answers do not match intent survey flow.
  • An invalid value in either the kind_of_care / form_of_contact field, showing an error message like: The Specified id (1a815f9c-8fe2-4a31-9728-550b92c4b077) is incorrect.

Rationale current question

To fetch the rationale for the current question, make a GET request to /api/mgp/v1/surveys/{survey_id}/questions/current/rationale.

cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/current/rationale" \
  -X "GET"

Responses

HTTP status code: 200

Rationale response is an object comprised of the following attributes:

  • message: string - a user-facing message that can be displayed to the patient
  • data: object - rationale raw data, contains:
    • type: string - a well defined code (r0-r6)
    • observation_params: list[string] - a list of observation IDs, relevant to prioritizing a question
    • condition_params: list[string] - a list of condition IDs, relevant to prioritizing a question

For more information about "data", see the “Engine API - Rationale” section on the Engine API page. Depending on the question type, the whole object or just a message can be returned.

Example: Questions from the dynamic part of the survey will return all of the data:

JSON
{
    "data": {
      "type": "r6",
      "observation_params": [
          {
              "id": "s_44",
              "name": "Joint pain",
              "common_name": "Joint pain"
          }
      ],
      "condition_params": []
    },
    "message": "We are asking this question to learn more about your Joint pain."
}

Example: Static questions that have rationale just return a message:

JSON
{
    "message": "We are asking this question to better understand the needs and motivations of patients using this checkup. Your answer will help us learn and improve our product."
}

HTTP status code: 404

Rationale not found - Survey or rationale not found

Fetch Rationale for previous question

If you need to fetch the rationale for a previous question, make a GET request to /api/mgp/v1/surveys/{survey_id}/questions/{question_index}/rationale. The question_index param is the sequence number of the question in the survey.

cURL
curl "https://api.infermedica.com/api/mgp/v1/surveys/1a815f9c-8fe2-4a31-9728-550b92c4b077/questions/5/rationale" \
  -X "GET"

Responses

HTTP status code: 200

Same as “Rationale current question” above.

HTTP status code: 404

Rationale not found - Survey or rationale not found

HTTP status code: 409

Cannot fetch question - Question does not exist

Question object

The question object contains the necessary information that the user needs to answer the question.

Example question

JSON
{
  "id": "sex",
  "index": 1,
  "question": {
    "text": "What is your sex?"
  },
  "answer_type": "choice",
  "meta": {
    "answers": [
      {
        "id": "female",
        "label": "Female"
      },
      {
        "id": "male",
        "label": "Male"
      }
    ],
    "has_rationale": false
  },
  "user_answer": {
    "answer": {
      "id": "female"
    }
  }
}

Fields

id (str)

ID that identifies the question.

index (number)

Ordinal number of the questions in the survey (0-based index).

question (object)

text (str) – Question text.

answer_type (str)

The type of answer to the given question.

meta (object)

  • has_rationale (bool) – Indicates whether the question may include an explanation or reasoning that can be retrieved using the rationale endpoint.
  • answers (list, optional) – Possible answers.
  • required (bool, optional) – Is the answer required? If not specified, the question requires an answer.
  • source_list_url (str, optional) – Specified if answer_type is list. Contains URL to list values allowed in given question.
  • max_length (number, optional) – Specified if answer_type is text. Maximum number of characters allowed in answer.
  • min_value (number, optional) – Specified if answer_type is number. Minimum value of the answer.
  • max_value (number, optional) – Specified if answer_type is number. Maximum value of the answer.
  • component (str, optional) – Specified if answer_type is symptoms. Possible values: single, group_single, group_multiple. Information on how to handle this question.
  • subcomponent (str, optional) – Specifies the subcomponent type for special question types. Possible values: scale, abdominal_pain.
  • evidence_id (str, optional) – Specified if answer_type is duration. Evidence ID associated with the question.
  • description (str, optional) – Additional description providing context for the question.
  • explication (str, optional) – Explanation text that can be displayed to users, typically answering "What does it mean?".
  • instruction (list[str], optional) – List of instructions for the user, typically answering "How to check it?".
  • placeholder (str, optional) – Placeholder text for the answer input field.
  • error (str, optional) – Error message to display when answer validation fails.
  • client_name (str, optional) – Name of the client associated with the question.
  • demographics (object, optional) – Demographic data collected during the prefill phase.
  • alerts (list, optional) – A list of alerts generated during interview processing, with each alert following the Alert schema. These alerts identify high-risk situations that may require safety measures or other interventions. The Alert schema includes the following properties:
    • type (str) – The type of alert. Supported types include:
      • soft_stop – Indicates the detection of high-risk symptoms.
      • hard_stop – A more critical alert for specific high-risk symptoms that are configured to require an immediate stop or intervention.
    • reasons (list) – A list of reasons for the alert, indicating detected risk factors. Possible string values include:
      • suicide_attempt – Detected history of suicide attempts.
      • suicidal_intent – Detected signs of intent to harm oneself.
      • suicidal_thoughts – Detected signs of suicidal thoughts.
      • emergency – Triggered by an answer that indicates an emergency situation.

user_answer (object, optional)

User's answer to this question, if it was given.

Skipping a question and answering none

Use the question object to decide what the user can do. Do not rely on question IDs, which can differ between instances.

  • meta.required tells you whether the question can be skipped. If it is omitted, the question requires an answer. If it is false, skip the question by sending null.
  • meta.answers tells you which escape options to show, such as “Other”, “Don’t know”, or “Not measured”. Show an escape option only when it appears in meta.answers or in an item’s choices. Do not add your own.

An empty list is rejected with The answer cannot be empty, even when the question is optional. To send no selection, use null.

Example: skip an optional question

JSON
{
  "answer": null
}

Summary by answer type

answer_typenull accepted“None”“Don’t know” or similar
multiple_choiceOnly if meta.required is falsenull on an optional questionListed option in meta.answers, if present
choiceOnly if meta.required is falseListed option in meta.answers, if presentListed option in meta.answers, if present
symptoms, component singleNochoice_id: absentchoice_id: unknown
symptoms, component group_singleNoListed item in meta.answers, if presentListed item in meta.answers, if present. To skip, send unknown for every item
symptoms, component group_multipleNochoice_id: absent on each itemchoice_id: unknown on each item
listOnly if meta.required is falseNot availableNot available
textOnly if meta.required is falseNot availableNot available
ageNoNot availableNot available
durationNoNot availableNot available

The sections below give the details for each type.

Multiple choice

If meta.required is false, send null when the user selects none of the listed options.

Each selected option is recorded as present. Options the user does not select are not recorded as absent. They are left out of the evidence, so null means the user reported none of them, not that each one was ruled out.

If the question is required, null is rejected and the user must select at least one option from meta.answers. When meta.answers contains an option such as “Other”, it is sent like any other option.

Example: none of the listed options

JSON
{
  "answer": null
}

Choice

Send one id from meta.answers. An escape option, such as “I can’t remember”, is an ordinary entry in meta.answers and is sent by its id. Send null only when meta.required is false.

Symptoms

Symptom questions reject null. Choose the payload based on meta.component. The IDs in the examples below are illustrations only.

single

Send exactly one object. choice_id is one of the item’s choices: usually present (Yes), absent (No), or unknown (Don’t know). Take labels from the item’s choices.

Example: “Don’t know”

JSON
{
  "answer": [
    { "id": "s_476", "choice_id": "unknown" }
  ]
}

group_single

Send exactly one object, the item the user selected, with choice_id set to present.

Some questions include escape items, such as “Don’t know” or “Not measured”, in meta.answers. These are ordinary items: send the item’s id with choice_id set to present. Whether an escape item appears depends on the question, so show one only when it is listed.

Example: the user selects a “Not measured” item

JSON
{
  "answer": [
    { "id": "s_2014", "choice_id": "present" }
  ]
}

To let the user skip the question, send every item in meta.answers with choice_id set to unknown. This matches how a skipped question is handled in Infermedica’s Symptom Checker. The payload is accepted even when unknown is not one of the item’s choices, and each item is recorded as unknown. This is the only case where more than one object is allowed. Any other payload with more than one object returns: For a group single question, only one answer can be given unless you want to skip this question by marking all choices as 'unknown'.

Example: skip a group single question

JSON
{
  "answer": [
    { "id": "s_2018", "choice_id": "unknown" },
    { "id": "s_2019", "choice_id": "unknown" },
    { "id": "s_2022", "choice_id": "unknown" }
  ]
}

group_multiple

Send one object for every item in meta.answers. If an item is missing, the answer is rejected. Each choice_id must be one of the item’s choices, usually present (Yes), absent (No), or unknown (Don’t know).

  • If a statement does not apply to the user, send absent.
  • If the user does not know, send unknown.

There is no single “none of these” payload and no separate skip payload. To answer none, send absent for every item. If you send unknown for every item, each item is recorded as unknown. The question still counts as answered.

Example

JSON
{
  "answer": [
    { "id": "p_7", "choice_id": "present" },
    { "id": "p_9", "choice_id": "absent" },
    { "id": "p_264", "choice_id": "unknown" }
  ]
}

List

Send at least one id. If meta.required is false, you can send null instead. Lists have no “none” option. When the user can answer “none”, it is usually asked in an earlier yes/no question.

Text

If meta.required is false, send null to skip the question. If the question is required, null is rejected.

Age and duration

Send a value. null is rejected. These questions have no “none” or “don’t know” payload.

Answer types

The answer structure will be different depending on the value of answer_type in the question object. This section describes the possible answer types.

Multiple choice

Example question object

JSON
{
  "id": "visit_reason",
  "index": 0,
  "question": {
    "text": "What is the main reason for your visit?"
  },
  "answer_type": "multiple_choice",
  "meta": {
    "answers": [
      {
        "id": "symptoms",
        "label": "I have worrying symptoms"
      },
      {
        "id": "test-results",
        "label": "I want to discuss the test results"
      },
      {
        "id": "extend-prescription",
        "label": "I want to extend my prescription"
      },
      {
        "id": "follow-up",
        "label": "I have a follow-up visit"
      },
      {
        "id": "other",
        "label": "Other"
      }
    ],
    "has_rationale": false
  }
}

Example answer

JSON
{
  "answer": [
    {
      "id": "other"
    },
    {
      "id": "test-results"
    }
  ]
}

Answer body

answer (list)

Object list. Each object must contain an id that coincides with the possible values defined in the meta.answers field in the question object. On an optional checklist, null means none of the listed options; a required checklist rejects null. See Skipping a question and answering none.

Choice

Example question object

JSON
{
  "id": "sex",
  "index": 1,
  "question": {
    "text": "What is your sex?"
  },
  "answer_type": "choice",
  "meta": {
    "answers": [
      {
        "id": "female",
        "label": "Female"
      },
      {
        "id": "male",
        "label": "Male"
      }
    ],
    "has_rationale": false
  }
}

Example answer

JSON
{
  "answer": {
     "id": "female"
   }
}

Answer body

answer (object)

Object must contain an id that coincides with the possible values defined in the meta.answers field of the question object. You can only choose one possible option. Send null only when meta.required is false. See Skipping a question and answering none.

Age

Example question object

JSON
{
  "id": "age",
  "index": 2,
  "question": {
    "text": "How old are you?"
  },
  "answer_type": "age",
  "meta": {
    "min_value": 18,
    "max_value": 130,
    "has_rationale": false
  }
}

Example answer

JSON
{
  "answer": {
    "value": 30,
    "unit": "year"
  }
}

Answer body

answer (object)

  • value (number) - A value consisting of an integer within the range defined in the question object (must be between meta.min_value and meta.max_value).
  • unit (str) - A unit of age. It can be year or month.

Age requires a value. null is rejected. See Skipping a question and answering none.

List

Example question object

JSON
{
  "id": "symptoms",
  "index": 5,
  "question": {
    "text": "Add your symptoms"
  },
  "answer_type": "list",
  "meta": {
    "source_list_url": "/v1/knowledge/symptoms?age=39&sex=female&language=en",
    "has_rationale": false
  }
}

Example data from knowledge endpoint

JSON
{
  "self": "https://api.infermedica.com/api/mgp/v1/knowledge/symptoms?age=31&sex=male&language=en&limit=5&cursor=5",
  "first": "https://api.infermedica.com/api/mgp/v1/knowledge/symptoms?age=31&sex=male&language=en&limit=5&cursor=0",
  "prev": "https://api.infermedica.com/api/mgp/v1/knowledge/symptoms?age=31&sex=male&language=en&limit=5&cursor=4",
  "next": "https://api.infermedica.com/api/mgp/v1/knowledge/symptoms?age=31&sex=male&language=en&limit=5&cursor=6",
  "last": "https://api.infermedica.com/api/mgp/v1/knowledge/symptoms?age=31&sex=male&language=en&limit=5&cursor=330",
  "items": [
    {
      "id": "s_582",
      "name": "Anxiety attack"
    },
    {
      "id": "s_1800",
      "name": "Appendix removal in the past"
    },
    {
      "id": "s_6",
      "name": "Appetite for salty foods"
    },
    {
      "id": "s_1010",
      "name": "Apraxia"
    },
    {
      "id": "p_254",
      "name": "Arm injury"
    }
  ]
}

Example answer

JSON
{
  "answer": [
    {
      "id":"s_1096"
    }
  ]
}

Answer body

answer (list)

Object list. Each object must contain an ID that coincides with the possible values defined in the additional endpoint defined in meta.source_list_url field. To fetch possible values, make a GET request to the endpoint defined in the meta.source_list_url field. Each object in the list required id field. Send at least one id, or null if meta.required is false. See Skipping a question and answering none.

Knowledge endpoints

To answer a question with answer_type equal to list you must call one of the knowledge endpoints. These endpoints provide information about specialists, symptoms, etc.

List of supported endpoints

  • /api/mgp/v1/knowledge/symptoms
  • /api/mgp/v1/knowledge/chronic_diseases
  • /api/mgp/v1/knowledge/specialists
  • /api/mgp/v1/knowledge/hospitalizations

To be able to search for elements in a list, you may pass the query parameter in URL to filter elements by name.

Text

Example question object

JSON
{
  "id": "comment",
  "index": 10,
  "question": {
    "text": "Just one last thing, add anything else that you would like your doctor to know."
  },
  "answer_type": "text",
  "meta": {
    "max_length": 400,
    "has_rationale": false
  }
}

Example answer

JSON
{
  "answer": "Example message to doctor"
}

Answer body

answer (str)

A string. Cannot be longer than the value defined in the meta.max_length field of the question object. When meta.required is false, skip the question with null. See Skipping a question and answering none.

Symptoms

Example question object

JSON
{
  "id": "risk_factors",
  "index": 3,
  "question": {
    "text": "Please check all the statements below that apply to you"
  },
  "answer_type": "symptoms",
  "meta": {
    "component": "group_multiple",
    "answers": [
      {
        "id": "p_7",         // id
        "name": "Obesity",
        "choices": [
          {
            "id": "present", // choice_id
            "label": "Yes"
          },
          {
            "id": "absent",
            "label": "No"
          },
          {
            "id": "unknown",
            "label": "Don't know"
          }
        ]
      },
      {
        "id": "p_9",
        "name": "Diagnosed hypertension",
        "choices": [
          {
            "id": "present",
            "label": "Yes"
          },
          {
            "id": "absent",
            "label": "No"
          },
          {
            "id": "unknown",
            "label": "Don't know"
          }
        ]
      }
    ],
    "has_rationale": false
  }
}

Example answer

JSON
{
  "answer": [
    { "id": "p_7", "choice_id": "present" },
    { "id": "p_9", "choice_id": "absent" }
  ]
}

Answer body

answer (list)

Object list. Each object must contain an id and choice_id that coincides with the possible values defined in the meta.answers field in the question object. Answers should be handled in different ways depending on the meta.component present. See Skipping a question and answering none for “Don’t know”, “Not measured”, and skip payloads.

  • single – exactly one object. choice_id is one of that item’s choices. “Don’t know” is unknown.
  • group_single – exactly one object with choice_id set to present. Escape items such as “Don’t know” or “Not measured” are listed in meta.answers when available and are sent as present. To skip the question, send every item with choice_id set to unknown.
  • group_multiple – one object for every item. Each choice_id is present, absent, or unknown. A statement that does not apply to the user is absent.

Duration

ℹ️

Question duration type is not enabled by default. It can be enabled during the initial instance configuration or any time afterwards.

Example question object

JSON
{
  "id": "interview",
  "index": 12,
  "question": {
    "text": "How long have you had abdominal pain?"
  },
  "answer_type": "duration",
  "meta": {
    "component": "duration",
    "evidence_id": "s_13",
    "has_rationale": false
  }
}

Example answer

JSON
{
  "answer": [
    {
      "id": "s_13",
      "duration": {
        "value": 5,
        "unit": "day"
      }
    }
  ]
}

Answer body

answer (list)

Object list with one element only. Object must contain an id that coincides with meta.evidence_id field in the question object and duration object with value and unit. Duration requires a value. null is rejected. See Skipping a question and answering none.

Possible duration units: minute, hour, day, week

Was this page helpful?