A clinic app sends a list of items it would like. The patient's health
app shows the list, the patient decides what to share, and the health
app answers with records and one outcome per item. This page walks
through that JSON with one running example. Every example on it is
checked against the client library's validators when the site is built.
Words on this page, and in the spec:
clinic app = Verifier · the patient's wallet app = Wallet ·
patient = Holder · record = Artifact.
Tags like XV-2 link to the requirement in the
spec, which is the authority where this page and it differ.
At a glance
A clinic asks for five items. The patient shares four of them and
declines insurance. Every item id appears once in the outcomes. Records
name the items they answer. Point at an id to follow it across.
Two rules hold the model together. Every item gets exactly one row in
requestStatus[]. Every record lists the item ids it answers in
fulfills[]. One record can answer several items, and one item
can be answered by several records.
The request
The app builds this object and hands it to the wallet.
Short and unique within the request. The response refers to the item by this id. ITEM-1
title
What the patient sees.
summary
Optional. One more line for the patient.
required
Optional. Tells the patient the clinic needs this item.It is advice only. The patient can still decline, and the wallet can still answer unavailable. HOLD-3
Media types the app can read for this item, most preferred first. ACC-1
What an item can ask for
content.kind is either selection.fhir (share records the
patient already has) or form.fhir (fill in a form). A wallet
that sees a kind it doesn't know answers unsupported for that
item and handles the rest of the request as usual SEL-9. The same
goes for a selector whose members have the wrong types, such as a
profilesFrom that is a string SEL-10.
An exact profile
Records that claim this StructureDefinition in meta.profile. List several to accept any of them.
Keep canonical strings exactly as written, including any
|versionCAN-2. A wallet reports
fulfilled for a versioned profile only when a returned record
claims that exact version CAN-5. See
Versions in canonicals.
A profile family
Any profile from an implementation guide, such as all of US Core. A
profile belongs to the family when its URL starts with the family URL
and a /SEL-5. Add resourceTypes to narrow it. If
profiles is also present, it widens the match rather than
narrowing it SEL-3.
Leave out all three filters to let the patient and their wallet
decide what's relevant for the visit. Partial answers are expected SEL-7.
{ "id": "anything-helpful", "title": "Anything else that would help your visit", "content": { "kind": "selection.fhir" }, "accept": ["application/fhir+json", "application/smart-health-card"]}
A form by URL
The wallet finds the Questionnaire from its canonical URL CAN-4, shows it,
and returns a QuestionnaireResponse whose questionnaire is the same
string FORM-5. If it can't load the form, it answers unsupported or
error rather than guessing FORM-4.
Send the whole Questionnaire when it isn't published anywhere. You can
send both: the canonical names the form and the inline copy is what
gets shown FORM-2. Without a canonical, the answers'
questionnaire is the inline form's url, plus
|version if it has one FORM-5.
A canonical can name one version of a form or profile by adding
| and the version. The text before the first | is the
URL; the rest is the version CAN-1.
The wallet looks the form up any way it likes: a cache, a FHIR server search, or fetching the bare URL …/phq-2.json.
It checks what it got: a Questionnaire whose url is exactly …/phq-2.json and whose version is exactly 1. Anything else doesn't count, and the item is unsupportedCAN-4.
The answers carry "questionnaire": "…/phq-2.json|1", the request's string unchanged FORM-5.
The same applies to profiles[]: a record counts toward
…|1.2 only if its meta.profile has exactly that string CAN-5.
What the patient sees
The wallet shows the purpose and each item's title and summary.
For each item it finds matching records, or shows the form.
The patient shares, leaves out, or fills in each item. They can share less than was asked for, and the wallet can offer other records that would help.
The wallet sends back the records and one outcome per item.
The patient decides item by item HOLD-1. If they review the
request and decline everything, the wallet still answers, with every
item declined. If they close it without reviewing, nothing comes
back and the browser call ends with an error HOLD-4.
Text in the request is not proof of who is asking. The browser and the
wallet's trust decisions establish that, outside the JSON, so the request
must not carry names, logos, or URLs claiming to identify the clinic
ID-1ID-2.
fulfilled and partial should come with at least one record
that lists the item ART-7. The others usually come with none.
What the app checks
Before using a response, the app checks it against the request it sent.
One bad record or status row costs only that record or item; the rest of
the response is still used. The client library does this for you, and the
SMART Testing EHR runs the same checks
against your wallet.
These reject the whole response
It isn't valid JSON, or type, version, artifacts, or requestStatus is wrong. XV-1
requestId isn't the request's id: it answers some other request. XV-2
These affect only one item
An item with no status row, two rows, or a status code outside the six has no valid outcome. Rows for ids not in the request are ignored. XV-3
A fulfilled or partial item that no valid record lists is flagged. XV-12
A fulfilled versioned-profile item needs a record claiming that exact version. XV-11
These set aside one record
A record with a duplicate id, no mediaType, or a fulfills[] naming items that aren't in the request. XV-5
A mediaType that isn't a known type, or isn't in the accept[] of every item it lists. XV-6XV-7
FHIR JSON without a fhirVersion or a resource in value, or (usually) in a release the request didn't list. XV-8
A health card without verifiableCredential[], or with an outer fhirVersion. XV-9
Form answers whose questionnaire isn't the requested canonical, exactly. XV-10
A set-aside record doesn't count toward the items it lists XV-4.
Several valid records for one item are fine; the app looks at all of them MM-2.
Problems below the JSON, in the mdoc envelope, are warnings rather than
failures; see Security and timeouts.
Passing these checks means the response is well formed. Whether to
trust a health card's issuer XV-13 or to file a record into the chart
is up to the clinic.
Complete example
The request and response from At a glance, in full.