On this page

A [`QuestionnaireResponse`](/content/docs/api/fhir/resources/questionnaireresponse/index.html) captures what a patient or clinician submitted. Downstream systems – analytics, search, CDS, exchange – usually need that turned into concrete FHIR resources: [`Observation`](/content/docs/api/fhir/resources/observation/index.html), [`Condition`](/content/docs/api/fhir/resources/condition/index.html), orders, and similar. This applies across charting, intake, registration, prior authorization, and other workflows.

Medplum supports two parsing approaches. You can use both in the same application – different Questionnaires can use different methods depending on their complexity.

## Choosing an Approach

|  | SDC annotations + [`$extract`](/content/docs/api/fhir/operations/extract/index.html) | Subscription + [Bot](/content/docs/bots/bot-for-questionnaire-response/index.html) |
| --- | --- | --- |
| How it works | Extraction rules live in the Questionnaire itself as FHIR extensions; `$extract` reads them and returns a Bundle | A Bot subscribes to `QuestionnaireResponse` creation; runs arbitrary TypeScript to write resources |
| Best for | Straightforward field-to-resource mappings; forms that change often | Scoring algorithms, conditional logic, multi-step workflows, external API calls |
| Change management | Edit the Questionnaire; no deployment needed | Redeploy Bot on logic changes; keep Bot and Questionnaire versions in sync |
| Limitations | Complex branching or external lookups get unwieldy | Requires Bot infrastructure; harder to inspect logic from the Questionnaire alone |

Pick `$extract` when the mapping is mostly one field → one resource field, and you want the logic to live beside the form definition.

Pick a Bot when you need to score a PHQ-9, write resources conditionally, call an external service, or otherwise do something that does not fit a declarative template.

You can also combine them: use `$extract` for simple demographic or intake data, and a Bot for the clinical scoring logic on the same submission.

For visit-level orchestration that launches forms and orders together, see [Visit Templates and the SOAP Approach](/content/docs/charting/visit-templates/index.html).

## Approach 1: SDC Annotations + $extract

Annotate the `Questionnaire` with template resources and FHIRPath extraction rules. When a `QuestionnaireResponse` is submitted, call [`$extract`](/content/docs/api/fhir/operations/extract/index.html); Medplum reads the annotations and returns a [transaction Bundle](/content/docs/fhir-datastore/fhir-batch-requests/index.html) of populated resources ready to upload.

### Annotating the Questionnaire

Medplum implements [template-based extraction](https://build.fhir.org/ig/HL7/sdc/extraction.html#template-extract), which requires the Questionnaire resource to contain template resources and the rules for populating the templates from a QuestionnaireResponse. The template resources (e.g. `Observation` or other resource types) are placed in `Questionnaire.contained` and given and internal reference `id`; a corresponding [`templateExtract` extension](https://build.fhir.org/ig/HL7/sdc/StructureDefinition-sdc-questionnaire-templateExtract.html) on the `Questionnaire` or one of its descendant items initiates extraction into that resource.

```json
{

"resourceType": "Questionnaire",

"status": "draft",

"contained": [

{

"resourceType": "Patient",

"id": "patientTemplate"

// ...

}

],

"extension": [

{

"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtract",

"extension": [{ "url": "template", "valueReference": { "reference": "#patientTemplate" } }]

}

]

//...

}
```

The location of the `templateExtract` extension determines the initial context for the extraction: if placed at the root of the `Questionnaire`, the entire `QuestionnaireResponse` will be in scope for FHIRPath rules to extract data from. If placed on a specific item, only the corresponding item from the `QuestionnaireResponse` will be in scope, simplifying the extraction rules for that response item if it can be extracted in isolation.

Within the template resources, [`templateExtractValue`](https://build.fhir.org/ig/HL7/sdc/StructureDefinition-sdc-questionnaire-templateExtractValue.html) and [`templateExtractContext`](https://build.fhir.org/ig/HL7/sdc/StructureDefinition-sdc-questionnaire-templateExtractContext.html) extensions work together to define the rules for extracting data from the `QuestionnaireResponse` into the template.

### Extraction Context

When the FHIRPath expression to extract a value is evaluated, the context on which it evaluates will initially be either the entire `QuestionnaireResponse` resource or a specific `QuestionnaireResponse.item`; the choice depends on whether the relevant `templateExtract` extension was placed at the top level of the `Questionnaire` or on a specific `Questionnaire.item`.

Combined with the value extraction logic described above for empty or multiple results, this can potentially produce resource JSON that is structurally invalid.

### Example

Corrected Questionnaire using templateExtractContext

```json
{

"resourceType": "Questionnaire",

"status": "draft",

// Extract extension at root of Questionnaire initiates extraction into specified template

"extension": [

{

"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtract",

"extension": [{ "url": "template", "valueReference": { "reference": "#patientTemplate" } }]

}

],

"contained": [

{

"resourceType": "Patient",

"id": "patientTemplate",

"name": [

{

// Context extension placed at top of the object to be inserted for each answer

"extension": [

{

"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractContext",

// Context expression linked to response items

"valueString": "item.where(linkId = 'name')"

}

],

"_text": {

// Nested value extensions are relative to parent context,

// and are evaluated separately for each result item

"extension": [

{

"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractValue",

"valueString": "answer.value.first()"

}

]

}

}

],

"telecom": [

{

"extension": [

{

"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractContext",

"valueString": "item.where(linkId = 'phone')"

}

],

"system": "phone",

"_value": {

"extension": [

{

"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractValue",

"valueString": "item.where(linkId = 'number').answer.value.first()"

}

]

},

"use": "home", // Default value for field specified

"_use": {

"extension": [

{

"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-templateExtractValue",

// Overrides the default if it returns a value

"valueString": "item.where(linkId = 'use').answer.value.first().code"

}

]

}

}

]

}

],

"item": [

{ "linkId": "name", "type": "string", "required": true },

{

"linkId": "phone",

"type": "group",

"repeats": true,

"required": true,

"item": [

{ "linkId": "number", "type": "string", "required": true },

{ "linkId": "use", "type": "choice", "answerValueSet": "http://hl7.org/fhir/ValueSet/contact-point-use" }

]

}

]

}
```

A corresponding `QuestionnaireResponse` shows how the data will be parsed:

```json
{

"resourceType": "QuestionnaireResponse",

"status": "completed",

"item": [

{

"linkId": "name",

"answer": [{ "valueString": "John Jacob Jingleheimer-Schmidt" }]

}

]

}
```

Value Extraction

The template extraction extensions are expected to contain [FHIRPath](https://hl7.org/fhir/fhirpath.html) expressions that return the value(s) to be inserted into the template. If no values are returned, the field is removed from the template; more than one result is inserted as an array of values. Using functions like `first()` in the expression can help ensure the correct number of values are returned and ensure the resulting resource is well-formed.

### Gathering Additional Data

If data from additional resources is required to populate the templates, search queries can be executed as part of the extraction process and their results stored in context to be operated on by later expressions. Queries are attached in context extensions using the [`application/x-fhir-query` language](https://hl7.org/fhir/fhir-xquery.html) to describe the search request, with the option to embed FHIRPath expressions as needed to construct the query string.

### Linking Extracted Resources

When the resources being extracted from the questionnaire response are related, such as the above `Patient` and `Observation`, you may want to link the extracted resources together with a reference like `Observation.subject`.
