Operations

The FHIR operations a DSP-FHIR server relies on. Each entry says what the op does for DSP data and why it's the right fit.

Canonical read — $graphql

What it does: returns a single, DSP-shaped projection of an encounter (conditions, orders, sections, provenance) from a published query document. See Canonical DSP read.

Why it fits: DSP is a rooted, encounter-scoped graph; a DSP client wants one call that returns that graph, not N typed searches. GraphQL is a FHIR base-spec operation and supports a profile-driven projection without inventing a DSP-specific wire protocol. Fallbacks for servers without GraphQL:


Change tracking — Encounter/$everything?_since=

What it does: returns a Bundle of everything in the encounter compartment touched since a given instant. Consumers derive DSP's NEW / UPDATED / DELETED flags from meta.versionId, meta.lastUpdated, and accompanying Provenance resources.

GET [base]/Encounter/enc-12345/$everything?_since=2026-04-23T14:00:00Z

=> 200 OK (Bundle, type=searchset)
// Derivation convention:
//   NEW     : meta.versionId == "1" AND meta.lastUpdated > _since
//   UPDATED : meta.versionId  > "1" AND meta.lastUpdated > _since
//   DELETED : tombstone OR Provenance.activity code = DELETE
//             (system http://terminology.hl7.org/CodeSystem/v3-DataOperation)
// Servers SHOULD emit a Provenance per mutation so DELETE is unambiguous.

Why it fits: FHIR already layers three change-tracking mechanisms at three granularities — $everything?_since= for per-encounter deltas, Bulk Data $export?_since= for patient-wide batches, _history for resource-level audit. The IG only has to pin the Provenance.activity vocabulary so DELETE is explicit.


Spoken-form lookup — CodeSystem/$lookup + ValueSet/$expand

What it does: resolves voice commands ("go to HPI", "open subjective") to canonical LOINC section codes, and vice versa. The IG publishes a spoken-form CodeSystem whose concepts carry designations for each voice alias; the two standard terminology ops cover both directions.

Forward (code → spoken forms):

GET [base]/CodeSystem/$lookup?system=http://loinc.org&code=10164-2&property=designation

=> 200 OK
{
  "resourceType":"Parameters",
  "parameter":[
    { "name":"display","valueString":"History of present illness Narrative" },
    { "name":"designation","part":[
      { "name":"use","valueCoding":{"system":"https://dsp-fhir.org/CodeSystem/spoken-form-use","code":"voice-alias"}},
      { "name":"value","valueString":"HPI" }
    ]},
    { "name":"designation","part":[
      { "name":"use","valueCoding":{"system":"https://dsp-fhir.org/CodeSystem/spoken-form-use","code":"voice-alias"}},
      { "name":"value","valueString":"history of present illness" }
    ]}
  ]
}

Reverse (spoken form → code):

GET [base]/ValueSet/dsp-section-spoken-forms/$expand?filter=HPI&includeDesignations=true

=> 200 OK
{
  "resourceType":"ValueSet",
  "expansion":{
    "contains":[
      { "system":"http://loinc.org","code":"10164-2","display":"History of present illness",
        "designation":[
          { "use":{"system":"https://dsp-fhir.org/CodeSystem/spoken-form-use","code":"voice-alias"},
            "value":"HPI" }
        ]
      }
    ]
  }
}

Why it fits: "spoken form" is a designation — exactly what CodeSystem.concept.designation was designed for. Every FHIR terminology server already implements $lookup and $expand; the IG's contribution is the vocabulary, not a new wire protocol.


Materialize follow-up — ActivityDefinition/$apply

What it does: turns a DSP follow-up ServiceRequest (carrying a boundsDuration) into a proposed Appointment.

1. Publish the template once, as an IG artifact:

{
  "resourceType":"ActivityDefinition",
  "id":"dsp-follow-up-appointment",
  "url":"https://dsp-fhir.org/ActivityDefinition/dsp-follow-up-appointment",
  "status":"active",
  "kind":"Appointment",
  "intent":"proposal",
  "timingDuration":{"value":30,"unit":"min","system":"http://unitsofmeasure.org","code":"min"},
  "participant":[
    { "type":"patient" },
    { "type":"practitioner" }
  ]
}

2. Invoke with the source ServiceRequest:

POST [base]/ActivityDefinition/dsp-follow-up-appointment/$apply

{
  "resourceType":"Parameters",
  "parameter":[
    { "name":"subject","valueReference":{"reference":"Patient/pat-67890"}},
    { "name":"encounter","valueReference":{"reference":"Encounter/enc-12345"}},
    { "name":"basedOn","valueReference":{"reference":"ServiceRequest/fu-001"}},
    { "name":"practitioner","valueReference":{"reference":"Practitioner/pract-001"}}
  ]
}

=> 200 OK

{
  "resourceType":"Appointment","id":"appt-0042","status":"proposed",
  "basedOn":[{"reference":"ServiceRequest/fu-001"}],
  "participant":[
    { "actor":{"reference":"Patient/pat-67890"},"status":"needs-action" },
    { "actor":{"reference":"Practitioner/pract-001"},"status":"tentative" }
  ],
  "extension":[
    { "url":"https://dsp-fhir.org/StructureDefinition/approximate-match","valueBoolean":true }
  ]
}

Why it fits: $apply is FHIR's purpose-built op for "turn a clinical intent into proposed action resources". An ActivityDefinition with kind=Appointment is exactly the template shape a DSP follow-up needs.

Scope. $apply produces a proposed Appointment — it does not find an open slot. Slot-finding is a scheduling-service concern outside the IG; clients either pass Appointment.start as a hint, run Appointment.$find, or leave it to a human.

Accompanying party — RelatedPerson/$match

What it does: resolves DSP's free-string accompanied_by ("Jane Doe, spouse") to a real RelatedPerson resource.

POST [base]/RelatedPerson/$match

{
  "resourceType":"Parameters",
  "parameter":[
    { "name":"resource","resource":{
        "resourceType":"RelatedPerson",
        "patient":{"reference":"Patient/pat-67890"},
        "relationship":[{
          "coding":[{
            "system":"http://terminology.hl7.org/CodeSystem/v3-RoleCode",
            "code":"SPS","display":"spouse"
          }]
        }],
        "name":[{"text":"Jane Doe"}]
    }},
    { "name":"onlyCertainMatches","valueBoolean":false },
    { "name":"count","valueInteger":3 }
  ]
}

=> 200 OK

{
  "resourceType":"Bundle","type":"searchset",
  "entry":[
    { "fullUrl":"https://example.org/RelatedPerson/rp-5512",
      "resource":{ "resourceType":"RelatedPerson","id":"rp-5512" },
      "search":{
        "mode":"match",
        "score":0.88,
        "extension":[
          { "url":"http://hl7.org/fhir/StructureDefinition/match-grade",
            "valueCode":"probable" }
        ]
      }
    }
  ]
}

Why it fits: the signature mirrors FHIR base Patient/$match — the canonical pattern for resolving a weakly-identified human to a real resource — so the shape is immediately familiar to every FHIR implementer. Da Vinci HRex's $member-match is the closest prior art. RelatedPerson/$match is not in the base spec; the IG profiles a parallel op rather than invent a DSP-specific name.


Turn-ref integrity — $validate

What it does: surfaces broken transcript turn-refs (integer indices that no longer resolve after the transcript is revised) as standard invariant violations on the resource.

Invariant on the transcript-turn-refs extension:

{
  "resourceType":"StructureDefinition",
  "url":"https://dsp-fhir.org/StructureDefinition/transcript-turn-refs",
  "derivation":"constraint",
  "differential":{
    "element":[{
      "id":"Extension",
      "constraint":[{
        "key":"turn-refs-resolve",
        "severity":"error",
        "human":"Every turn index MUST resolve in the referenced DocumentReference version.",
        "expression":"<server-evaluated - see note>"
      }]
    }]
  }
}

Invocation:

POST [base]/MedicationRequest/med-001/$validate

=> 200 OK
{
  "resourceType":"OperationOutcome",
  "issue":[
    { "severity":"error","code":"invariant",
      "diagnostics":"turn-refs-resolve: MedicationRequest/med-001 references turn 11; transcript revision 3 has only 9 turns.",
      "location":["MedicationRequest.extension('transcript-turn-refs').extension('turn')[0]"] }
  ]
}

Why it fits: "is this resource well-formed against a profile" is what $validate does. The turn-ref rule is a profile invariant, not a new operation. $validate is on every FHIR server; the rule is discoverable via the profile; clients can run it defensively. Normative rule R1 carries the prevention side; $validate surfaces violations when they slip through.


$ground — transcript turn-join with context

What it does: given a resource with a transcript-turn-refs extension, returns the referenced turns (with an optional ±N context window) from the pinned transcript version. The only DSP-specific operation in the IG.

GET [base]/MedicationRequest/med-001/$ground?include-content=true&context-window=1

=> 200 OK

{
  "resourceType":"Parameters",
  "parameter":[
    { "name":"transcript","valueReference":{"reference":"DocumentReference/dr-transcript-001/_history/3"}},
    { "name":"turn","part":[
      { "name":"index","valueInteger":10 },
      { "name":"speaker","valueCode":"provider" },
      { "name":"start-time","valueString":"00:01:40.1" },
      { "name":"end-time","valueString":"00:01:42.7" },
      { "name":"content","valueString":"So for the bronchitis..." },
      { "name":"role","valueCode":"context" }
    ]},
    { "name":"turn","part":[
      { "name":"index","valueInteger":11 },
      { "name":"speaker","valueCode":"provider" },
      { "name":"content","valueString":"Let's start azithromycin 250 daily for five days." },
      { "name":"role","valueCode":"grounding" }
    ]}
  ]
}

Why it fits (and is custom): no base-spec or IG op dereferences integer turn indices into turn content. Provenance records the linkage but not the text; $everything hands back the whole transcript and leaves the join to the client. The server wrote the transcript and knows its format — it's the natural owner of the join. Pinning _history/3 in the response keeps normative rule R1 (turn-index stability) end-to-end.


SearchParameters & capability advertisement

Three DSP concerns close with indexing + capability advertisement, not operations:

Index the confidence-score extension and use FHIR's cross-type search to build a review queue.

{
  "resourceType":"SearchParameter",
  "url":"https://dsp-fhir.org/SearchParameter/dsp-confidence",
  "name":"confidence",
  "base":["MedicationRequest","ServiceRequest","Condition","Observation"],
  "code":"confidence",
  "type":"number",
  "expression":"extension('https://dsp-fhir.org/StructureDefinition/confidence-score').valueDecimal"
}

// Cross-type review queue — one call, multiple resource types:
GET [base]/?_type=MedicationRequest,ServiceRequest,Condition,Observation
          &encounter=Encounter/enc-12345
          &confidence=lt0.8
          &_sort=confidence

Payload-version negotiation — CapabilityStatement extension

Advertise accepted and emitted DSP payload versions on CapabilityStatement.rest.resource.extension. Clients read CapabilityStatement already.

{
  "resourceType":"CapabilityStatement",
  "rest":[{
    "mode":"server",
    "extension":[
      { "url":"https://dsp-fhir.org/StructureDefinition/dsp-payload-versions",
        "extension":[
          { "url":"accepts","valueCode":"1.0.0" },
          { "url":"emits",  "valueCode":"1.0.0" },
          { "url":"emits",  "valueCode":"0.9.3" },
          { "url":"default-emit","valueCode":"1.0.0" }
        ]
      }
    ]
  }]
}

Servers denormalize the payload version to meta.tag so baseline FHIR search works:

GET [base]/Encounter?_tag=https://dsp-fhir.org/CodeSystem/payload-version|1.0.0

Normative rule R3: servers MUST advertise, MUST NOT auto-upgrade on read, and MUST reject unknown versions on write with 422.

Search terms — SearchParameter

DSP synonyms / search terms index cleanly as dsp-search-term (type string) over the search-terms extension.


Capability advertisement

A conformant DSP-FHIR server advertises the standard ops it relies on (so clients can feature-detect) alongside its SearchParameters. The only DSP-custom entry is $ground.

{
  "resourceType":"CapabilityStatement",
  "rest":[{
    "mode":"server",
    "operation":[
      { "name":"graphql",        "definition":"http://hl7.org/fhir/OperationDefinition/Resource-graphql" },
      { "name":"everything",     "definition":"http://hl7.org/fhir/OperationDefinition/Encounter-everything" },
      { "name":"lookup",         "definition":"http://hl7.org/fhir/OperationDefinition/CodeSystem-lookup" },
      { "name":"expand",         "definition":"http://hl7.org/fhir/OperationDefinition/ValueSet-expand" },
      { "name":"apply",          "definition":"http://hl7.org/fhir/OperationDefinition/ActivityDefinition-apply" },
      { "name":"match",          "definition":"http://hl7.org/fhir/OperationDefinition/Patient-match" },
      { "name":"validate",       "definition":"http://hl7.org/fhir/OperationDefinition/Resource-validate" },
      { "name":"document",       "definition":"http://hl7.org/fhir/OperationDefinition/Composition-document" },

      // IG-profiled (same signature as Patient-match):
      { "name":"match",          "definition":"https://dsp-fhir.org/OperationDefinition/RelatedPerson-match" },

      // DSP-custom:
      { "name":"ground",         "definition":"https://dsp-fhir.org/OperationDefinition/ground" }
    ],
    "searchParam":[
      { "name":"confidence",      "definition":"https://dsp-fhir.org/SearchParameter/dsp-confidence",      "type":"number" },
      { "name":"payload-version", "definition":"https://dsp-fhir.org/SearchParameter/dsp-payload-version", "type":"token"  },
      { "name":"search-term",     "definition":"https://dsp-fhir.org/SearchParameter/dsp-search-term",    "type":"string" }
    ]
  }]
}