Visit Templates and the SOAP Approach | Medplum

Visit Template Lifecycle

  1. Author a PlanDefinition whose action entries reference Questionnaires and ActivityDefinitions. Authoring detail lives in Authoring Clinical Protocols.
  2. Invoke $apply with subject (Patient) and optionally encounter, practitioner, and organization.
  3. Medplum creates Tasks (and ServiceRequests when ActivityDefinition.kind is ServiceRequest).
  4. Clinicians complete Questionnaires and orders; parse responses into FHIR resources using Parsing Questionnaire Responses or Bots.
  5. Sign the visit using ClinicalImpression.status and a Provenance on the Encounter (see Signing and Locking Notes).

Common Visit-Template Patterns

A few shapes recur in real implementations.

Avoid storing everything as raw QuestionnaireResponse only – answers there are not first-class searchable fields the way Observations and Conditions are. Parse into the proper resources (see Parsing Questionnaire Responses).

How Visits, FHIR, and SOAP Line Up

The diagram below is intentionally simplified – real encounters interleave steps – but shows how common visit steps map to FHIR resources and SOAP letters. Template mechanics (what $apply creates first) are separate from documentation; everything eventually references the same Encounter.

SOAP FHIR resources Visit steps
S Observations from questionnaires Tasks and parsing Patient-reported findings and forms
O Observations vitals and exam Vitals and measured exam data
A ClinicalImpression and Condition Assessment reasoning and diagnoses
P ServiceRequest MedicationRequest CarePlan Orders referrals meds follow-up

The encounter graph below shows the same resources hanging off a single Encounter:

Example: full SOAP note FHIR R4 Bundle

{
  "resourceType": "Bundle",
  "type": "collection",
  "entry": [
    {
      "fullUrl": "urn:uuid:example-encounter",
      "resource": {
        "resourceType": "Encounter",
        "id": "example-encounter",
        "status": "finished",
        "class": {
          "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
          "code": "AMB",
          "display": "ambulatory"
        },
        "subject": { "reference": "Patient/homer-simpson" },
        "participant": [
          {
            "individual": { "reference": "Practitioner/dr-alice-smith" }
          }
        ],
        "period": {
          "start": "2024-01-15T10:00:00Z",
          "end": "2024-01-15T11:30:00Z"
        }
      }
    },
    {
      "fullUrl": "urn:uuid:obs-subjective-fatigue",
      "resource": {
        "resourceType": "Observation",
        "id": "obs-subjective-fatigue",
        "status": "final",
        "code": {
          "coding": [
            {
              "system": "http://loinc.org",
              "code": "75325-1",
              "display": "Symptom"
            }
          ],
          "text": "Fatigue"
        },
        "subject": { "reference": "Patient/homer-simpson" },
        "encounter": { "reference": "Encounter/example-encounter" },
        "performer": [{ "reference": "Patient/homer-simpson" }],
        "valueString": "Patient reports feeling lethargic for the past week"
      }
    },
    {
      "fullUrl": "urn:uuid:obs-objective-heart-rate",
      "resource": {
        "resourceType": "Observation",
        "id": "obs-objective-heart-rate",
        "status": "final",
        "code": {
          "coding": [
            {
              "system": "http://loinc.org",
              "code": "8867-4",
              "display": "Heart rate"
            }
          ]
        },
        "subject": { "reference": "Patient/homer-simpson" },
        "encounter": { "reference": "Encounter/example-encounter" },
        "performer": [{ "reference": "Practitioner/dr-alice-smith" }],
        "valueQuantity": {
          "value": 112,
          "unit": "beats/min",
          "system": "http://unitsofmeasure.org",
          "code": "{Beats}/min"
        }
      }
    },
    {
      "fullUrl": "urn:uuid:clinical-impression-assessment",
      "resource": {
        "resourceType": "ClinicalImpression",
        "id": "clinical-impression-assessment",
        "status": "completed",
        "subject": { "reference": "Patient/homer-simpson" },
        "encounter": { "reference": "Encounter/example-encounter" },
        "date": "2024-01-15T11:00:00Z",
        "description": "Patient presents with fatigue and abdominal pain.",
        "finding": [
          { "itemReference": { "reference": "Condition/condition-gastritis" }}
        ],
        "note": [
          { "text": "Assessment: symptoms consistent with gastritis. Differential includes peptic ulcer disease. Will monitor response to treatment." }
        ]
      }
    },
    {
      "fullUrl": "urn:uuid:condition-gastritis",
      "resource": {
        "resourceType": "Condition",
        "id": "condition-gastritis",
        "clinicalStatus": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/condition-clinical",
              "code": "active"
            }
          ]
        },
        "verificationStatus": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/condition-ver-status",
              "code": "confirmed"
            }
          ]
        },
        "code": {
          "coding": [
            {
              "system": "http://hl7.org/fhir/sid/icd-10-cm",
              "code": "K29.70",
              "display": "Gastritis, unspecified, without bleeding"
            }
          ]
        },
        "subject": { "reference": "Patient/homer-simpson" },
        "encounter": { "reference": "Encounter/example-encounter" }
      }
    },
    {
      "fullUrl": "urn:uuid:service-request-lab",
      "resource": {
        "resourceType": "ServiceRequest",
        "id": "service-request-lab",
        "status": "active",
        "intent": "order",
        "code": {
          "coding": [
            {
              "system": "http://loinc.org",
              "code": "13958-0",
              "display": "Helicobacter pylori [Presence] in Stool by Immunoassay"
            }
          ]
        },
        "subject": { "reference": "Patient/homer-simpson" },
        "encounter": { "reference": "Encounter/example-encounter" },
        "requester": { "reference": "Practitioner/dr-alice-smith" }
      }
    },
    {
      "fullUrl": "urn:uuid:provenance-note-signed",
      "resource": {
        "resourceType": "Provenance",
        "id": "provenance-note-signed",
        "target": [{ "reference": "Encounter/example-encounter" }],
        "recorded": "2024-01-15T11:30:00Z",
        "reason": [
          {
            "coding": [
              {
                "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
                "code": "SIGN",
                "display": "Signed"
              }
            ]
          }
        ],
        "agent": [
          {
            "type": {
              "coding": [
                {
                  "system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type",
                  "code": "author"
                }
              ]
            },
            "who": { "reference": "Practitioner/dr-alice-smith" }
          }
        ]
      }
    }
  ]
}

Subjective and Objective – Observation

Both Subjective and Objective are Observation resources. The distinction is usually performer:

Use appropriate coding (typically LOINC) and value[x]. For measurement details see Observations and vital signs.

Example: patient-reported fatigue (Subjective)

{
  "resourceType": "Observation",
  "status": "final",
  "code": {
    "coding": [
      {
        "system": "http://loinc.org",
        "code": "75325-1",
        "display": "Symptom"
      }
    ],

"text": "Fatigue"
  },

"subject": { "reference": "Patient/homer-simpson" },

"encounter": { "reference": "Encounter/example-encounter" },

"performer": [{ "reference": "Patient/homer-simpson" }],

"valueString": "Patient reports feeling lethargic for the past week"
}

Example: elevated heart rate (Objective)

{
  "resourceType": "Observation",
  "status": "final",
  "code": {
    "coding": [
      {
        "system": "http://loinc.org",
        "code": "8867-4",
        "display": "Heart rate"
      }
    ]
  },

"subject": { "reference": "Patient/homer-simpson" },

"encounter": { "reference": "Encounter/example-encounter" },

"performer": [{ "reference": "Practitioner/dr-alice-smith" }],

"valueQuantity": {
    "value": 112,
    "unit": "beats/min",
    "system": "http://unitsofmeasure.org",
    "code": "{Beats}/min"
  }
}

Assessment – Clinical Impression

ClinicalImpression is the FHIR-native assessment resource – the “A” in SOAP.

Why ClinicalImpression instead of DocumentReference or raw QuestionnaireResponse?

Some apps store assessment as DocumentReference or leave narrative only in QuestionnaireResponse. ClinicalImpression gives findings, summary, and reasoning discrete fields other systems can consume. Prefer structured coded data and use free-text where clinicians need it.

Usually create ClinicalImpression early with statusin-progress, then transition to completed when signed.

Field Description Example
status Lifecycle state in-progress, completed
subject Patient Patient/homer-simpson
encounter Encounter Encounter/example-encounter
date When assessed 2024-01-15T10:00:00Z
description Short summary Patient presents with fatigue and abdominal pain.
note Narrative; note[0].text is common for the note Assessment narrative text

Example: ClinicalImpression at encounter start

{
  "resourceType": "ClinicalImpression",
  "status": "in-progress",
  "subject": { "reference": "Patient/homer-simpson" },
  "encounter": { "reference": "Encounter/example-encounter" },
  "date": "2024-01-15T10:00:00Z",
  "description": "Patient presents with fatigue and abdominal pain.",
  "note": [
    { "text": "Assessment: symptoms consistent with gastritis. Differential includes peptic ulcer disease. Will monitor response to treatment." }
  ]
}

Formal diagnoses are often modeled as Condition while ClinicalImpression carries reasoning. See Diagnoses and problem list.

Plan – Orders and Care

Plan items are concrete FHIR requests: ServiceRequest for labs, imaging, and referrals (use category to distinguish), MedicationRequest for prescriptions, and CarePlan for ongoing care strategy. Generate them inline from ActivityDefinition actions on the visit template rather than free text. See Ordering Labs and Imaging and Representing Prescriptions for detail.

Signing and Locking Notes

When the note is complete, set ClinicalImpression.status to completed and create Provenance targeting the Encounter to record signer and time. "Signed" and "locked" are separate product decisions – co-signing, post-sign editable windows, and amendment workflows belong in your own discovery; see Designing Charting for the structure-vs-narrative framing.

Example: Provenance for clinician sign-off

{
  "resourceType": "Provenance",
  "target": [{ "reference": "Encounter/example-encounter" }],
  "recorded": "2024-01-15T11:30:00Z",
  "reason": [
    {
      "coding": [
        {
          "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
          "code": "SIGN",
          "display": "Signed"
        }
      ]
    }
  ],
  "agent": [
    {
      "type": {
        "coding": [
          {
            "system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type",
            "code": "author"
          }
        ]
      },
      "who": { "reference": "Practitioner/dr-alice-smith" }
    }
  ]
}