Consent and Signatures | Medplum
The Consent Resource
A single Consent represents one agreement. Do not bundle several agreements into one resource — a patient who accepts treatment but declines a payment agreement needs two independently statused records.
| Element | Purpose |
|---|---|
status |
draft, proposed, active, rejected, inactive, or entered-in-error. A declined agreement is a rejected Consent, not a missing one. |
scope |
The broad context of the consent — privacy, treatment, research, or advance care directive. Required. |
category |
The type of consent document. Required, and repeatable so you can carry both a LOINC document type and an act code. |
patient |
The patient the consent is about. |
dateTime |
When the consent was given. This is the clinically meaningful date, distinct from meta.lastUpdated. |
performer |
Who granted the consent — the patient, or a RelatedPerson acting for them. |
organization |
The organization holding the consent. |
policy |
The governing agreement, as an authority plus a uri pointing at the actual document. |
policyRule |
A coded reference to a known regulatory policy. |
sourceAttachment / sourceReference |
The underlying artifact — see Linking a Signature to a Consent. |
verification |
Whether the consent was verified, with whom, and on what date. |
provision |
Fine-grained permit/deny rules. Most consent capture flows do not populate this. |
The example below is a privacy consent that governs data disclosure to a third-party e-prescribing vendor. Note that it uses policy with a live uri rather than policyRule, because the governing document is the vendor's terms of service rather than a coded regulation:
{
"resourceType": "Consent",
"status": "active",
"scope": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/consentscope",
"code": "patient-privacy",
"display": "Patient Privacy"
}
],
"text": "Patient Privacy"
},
"category": [
{
"coding": [
{
"system": "http://loinc.org",
"code": "59284-0",
"display": "Privacy Consent Document"
}
]
},
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
"code": "IDSCL",
"display": "information disclosure"
}
]
}
],
"patient": {
"reference": "Patient/e9232f44-6287-4506-8bbc-b4091a284054",
"display": "Frodo Baggins"
},
"dateTime": "2026-07-28T21:28:10.866Z",
"policy": [
{
"authority": "DoseSpot",
"uri": "https://dosespot.com/exhibit-a-terms-of-service/"
}
]
}
Coding a Consent
Consent coding is where most implementations diverge, because it encodes organizational policy rather than clinical fact. Three elements carry the meaning:
scopeuses consentscope —patient-privacy,treatment,research, oradr.categoryidentifies the document type. LOINC59284-0(Privacy Consent Document) is common, as are v3-ActCode values such asnopp,pay, andmed.policyRulepoints at a coded policy such ashipaa-npporhipaa-self-pay. Usepolicywith anauthorityanduriinstead when the governing document is a specific contract or terms-of-service page.
For a table mapping common intake consent types to specific scope, category, and policyRule combinations, see modeling Consent resources in intake questionnaires.
Status and Re-consent
Consent is not a one-time event. Policies change, patients move between sites, and many organizations re-consent annually. Model this as a sequence of resources rather than by editing one in place:
- The patient agrees →
status: active - The patient declines →
status: rejected(still a recorded decision, and still auditable) - A newer consent supersedes it → the prior Consent moves to
status: inactiveand a new Consent is created with the currentdateTime - The consent was recorded in error →
status: entered-in-error
Superseding rather than editing preserves the answer to "what had this patient agreed to on a given date," which is the question an audit actually asks.
Auditing Consent Changes
Medplum stores every version of every resource, so a consent carries its own audit trail with no additional configuration. In the Medplum App, open a Consent and use:
- History — every version, with the timestamp and the user account responsible. Selecting a version shows a diff against the prior one. Available directly at
https://app.medplum.com/Consent/:id/history. - Blame — the current resource annotated line by line with the version and user that last touched each field. This answers "who changed the status of this consent, and when" without reading through diffs.
- JSON — the raw resource, including the code systems and
meta.lastUpdated.
The same history is available over the API:
GET /fhir/R4/Consent/:id/_history
Capturing Consent in a Form
Most consents are captured as part of a larger form rather than on their own. In a patient intake flow, each acknowledgement in the questionnaire becomes its own Consent resource:
| Intake acknowledgement | scope |
category |
|---|---|---|
| Consent for Treatment | treatment |
med |
| Agreement to Pay for Treatment | treatment |
pay |
| Notice of Privacy Practices | patient-privacy |
nopp |
| Acknowledgement for Advance Directives | adr |
acd |
Two mappings matter when you write the extraction logic:
- The checkbox drives
status— checked becomesactive, unchecked becomesrejected. Creating nothing when the box is unchecked loses the fact that the patient was asked and declined. - The date field drives
dateTime, notmeta.lastUpdated. A form completed on paper and entered later has a consent date earlier than its creation timestamp.
Capturing a Digital Signature
Some consents need a handwritten signature rather than a checkbox. Add the questionnaire-signatureRequired extension to a Questionnaire and the QuestionnaireForm component renders a signature pad below the form and blocks submission until it is signed:
{
"resourceType": "Questionnaire",
"status": "active",
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/questionnaire-signatureRequired",
"valueCodeableConcept": {
"coding": [
{
"system": "urn:iso-astm:E1762-95:2013",
"code": "1.2.840.10065.1.12.1.1",
"display": "Author's Signature"
}
]
}
}
],
"item": [{ "linkId": "consent-text", "type": "display", "text": "..." }]
}
Pair the pad with a plain string item labeled "Print Name" when your compliance posture requires the signer's printed name alongside the mark.
Where the Signature Is Stored
On submit, the signature is written to the QuestionnaireResponse as a questionnaireresponse-signature extension holding a FHIR Signature:
{
"resourceType": "QuestionnaireResponse",
"status": "completed",
"authored": "2026-07-28T21:28:10.866Z",
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/questionnaireresponse-signature",
"valueSignature": {
"type": [
{
"system": "http://hl7.org/fhir/signature-type",
"code": "ProofOfOrigin",
"display": "Proof of Origin"
}
],
"when": "2026-07-28T21:28:10.866Z",
"who": { "reference": "Practitioner/dc1c2b39-9dd5-4f4a-8e7d-2b1e3a5c6d70" },
"data": "iVBORw0KGgoAAAANSUhEUg..."
}
}
]
}
The three fields that make this an evidentiary record are who (the authenticated profile that signed, defaulting to the logged-in user), when (the moment the stroke completed), and data (the signature image as a base64-encoded PNG). The submitted response also carries source and authored, so the signing identity is recorded independently of the signature itself.
Linking a Signature to a Consent
A signature captured on a QuestionnaireResponse is not automatically attached to the Consent resources extracted from it. Creating that link is part of your extraction logic, and it is what makes the consent record self-contained. Two options:
Reference the response. Consent.sourceReference accepts a QuestionnaireResponse, so the consent can point at the exact submission that produced it — signature extension included:
{
"resourceType": "Consent",
"status": "active",
"patient": { "reference": "Patient/e9232f44-6287-4506-8bbc-b4091a284054" },
"dateTime": "2026-07-28T21:28:10.866Z",
"sourceReference": { "reference": "QuestionnaireResponse/a1b2c3d4-5678-90ab-cdef-1234567890ab" }
}
This is the lighter-weight option and keeps one signature serving every consent extracted from the form.
Attach the artifact. Where each consent needs to stand alone — for disclosure to a payer, or export to another system — store the rendered document as a Binary and reference it from Consent.sourceAttachment. See Binary Data for upload mechanics.