# 05 · Treat

  A diagnosis costs one click while the clinician is still in the room. Reconstructed weeks
  later from a rejected claim, it costs somebody a morning, and what you end up with is a
  guess with a code on it.

## Why this stop exists

Between opening the encounter and billing for it, somebody is examined, something is found
and something is done. Every stop around this one already assumes that record exists.
Preauthorisation asks for the diagnosis behind the request. The claim carries one diagnosis
per intervention and is assessed on the pair. The patient's next facility needs to know what
happened at this one.

Without a stop of its own, all of that gets assembled at submission by whoever is closing
the claim. That is the wrong person at the wrong time, working from notes rather than from
the encounter.

This is an interchange, and the fork is an unusual one. One branch carries the clinical
record onward to the payer, and the other leaves the rail entirely for the shared health
record. The same act of recording feeds both, so you only do it once.

## What is recorded here

<Wire
  rows={[
    { call: "The diagnosis", does: "What was found, as an ICD-11 code taken from the terminology service. It is never typed by hand and never mapped from a local string at submission time.", keep: "diagnosis_id" },
    { call: "The link to the intervention", does: "Which billable intervention this diagnosis justifies. The payer assesses the pair, so a diagnosis with nothing attached fails, and so does an intervention with nothing behind it.", keep: "intervention_code" },
    { call: "The encounter itself", does: "The clinical facts as FHIR: observations, notes, impressions and the conditions treated. They are written to the shared health record through the same call.", keep: "bundle_id" },
    { call: "What was requested", does: "Orders and prescriptions. They are routed to whoever performs them, frequently not you, and answered back against the request.", keep: "order_id, prescription_id" },
    { call: "Where the patient goes next", does: "Referrals and specimens, carrying the record and the authorisation already taken here.", keep: "referral_id" },
  ]}
/>

The first two are what stop claims bouncing. The rest is what makes the record worth having,
because the same facts, recorded once, serve the claim, the next facility, the patient's own
record and, as the last section on this page explains, the documents the claim requires.

Recording clinically is the decision everything else rests on. The rest of this stop follows
from having done it.

## Take the code from the service, not from a list you keep

  `GET /api/v2/clinical/diagnoses` is not registered. The live coded-list surface is
  `/api/v1/terminology` — `/concepts`, `/concepts/{concept_id}` and `/value-sets` — which is where
  an ICD-11 search will resolve from, and which the
  [terminology reference](/rail/reference/Terminology-Service) documents in full.

  Recording a diagnosis is live, at `POST /api/v2/visits/{visit_ref}/diagnoses`. Reading them back
  off a visit and withdrawing one are not.

<ApiRef method="GET" path="/api/v2/clinical/diagnoses" to="/rail-api/05-treat">
  Search ICD-11 for a codable diagnosis in the release the payer is currently validating against.
</ApiRef>

Two properties of the response decide whether the claim survives.

<Wire
  rows={[
    { call: "codable", does: "ICD-11 contains groupings and chapter headings that are not diagnoses. They come back in a search and they are rejected at assessment. Offer only entries flagged codable.", keep: "codable: true" },
    { call: "version", does: "The release the payer validates against moves. A code cached from an older release can be retired without your picker noticing.", keep: "the version you resolved against" },
  ]}
/>

  They do not come from clinicians choosing badly. They come from pickers built once, from a
  spreadsheet, and never refreshed after that. The full walkthrough is at
  [fetching a coded list](/rail/reference/Value-Sets) and
  [pinning to a release](/rail/reference/Terminology-Pinning-Versions).

## Record it against the visit

<ApiRef method="POST" path="/api/v1/visits/{visit_id}/diagnoses" to="/rail-api/05-treat">
  Record a diagnosis on the visit, linked to the intervention it justifies.
</ApiRef>

<Anatomy
  cards={[
    {
      title: "Always",
      required: ["icd11_code", "description", "rank", "intervention_code"],
      note: "rank is primary or secondary. Exactly one primary per visit, any number of secondaries.",
    },
    {
      title: "Where the clinician knows it",
      optional: ["certainty", "onset", "recorded_by"],
      note: "certainty is confirmed, provisional or differential. A provisional diagnosis is a legitimate thing to record and to bill against, not a placeholder to be tidied up later.",
    },
  ]}
/>

Build the workflow around `intervention_code`. It is not metadata on the diagnosis; it is the
assertion the payer assesses. One diagnosis can justify several interventions, and several
diagnoses can sit behind one, so record the pair each time rather than recording a list of
codes and hoping the assessor infers the pairing.

## The record is amended, never rewritten

<ApiRef method="DELETE" path="/api/v1/visits/{visit_id}/diagnoses/{diagnosis_id}" to="/rail-api/05-treat">
  Withdraw a diagnosis recorded in error, while the visit is still open.
</ApiRef>

Withdrawal is available until the claim is submitted, and refused after it with
`DIAGNOSIS_LOCKED`. That is deliberate, because once a claim has been assessed against a
diagnosis, changing the diagnosis underneath it changes what the payer agreed to. Corrections
after submission are raised against the claim.

  Three surfaces on this page answer 404 in the service today: the visit-scoped clinical pair
  (`/api/v1/visits/{visit_id}/clinical`, which is also on the wrong version — the registered visits
  group is v2), the whole `/orders` prefix, and the whole `/referrals` prefix. Document generation
  under a visit is unbuilt too; `GET /api/v2/visits/{visit_ref}/documents` lists what is attached.

  Live at this stop: recording a diagnosis on the visit, episodes of care under
  `/api/v1/clinical/episodes-of-care`, and prescriptions. The reference marks each unbuilt operation
  where it appears, so a call you can run is distinguishable from one you cannot.

## Contribute the encounter

<ApiRef method="POST" path="/api/v1/visits/{visit_id}/clinical" to="/rail-api/05-treat">
  Send the encounter as a FHIR bundle. It is validated, written to the clinical repository, and acknowledged.
</ApiRef>

The bundle is a transaction, so it is written whole or not at all. A validation failure
returns `issues[]`, and each entry names the index and the element that failed, so you can fix
the thing it names instead of re-reading the payload.

<Anatomy
  cards={[
    {
      title: "Encounter",
      required: ["status", "class", "period"],
      note: "One per visit. Its class matches the access_point the visit was opened with, so an outpatient visit does not contribute an inpatient encounter.",
    },
    {
      title: "Condition",
      required: ["code", "clinicalStatus"],
      note: "The same ICD-11 codes recorded above. Send them here too rather than expecting the rail to derive one from the other; the diagnosis call is a payer assertion, this is the clinical record.",
    },
    {
      title: "Observation",
      required: ["code", "value"],
      note: "Vitals, results and measurements, LOINC-coded. This is what makes the record longitudinal rather than a list of visits.",
    },
    {
      title: "DocumentReference",
      required: ["type", "content"],
      note: "Clinical notes: the history, the examination and the plan. Coded by note type so another system can find the discharge summary without reading all of them.",
    },
  ]}
/>

Send it as the encounter progresses, not once at the end. Another facility can already see an
acknowledged resource, while a bundle held back until discharge is a record that did not exist
at the moment somebody needed it.

<ApiRef method="GET" path="/api/v1/visits/{visit_id}/clinical" to="/rail-api/05-treat">
  Read back what this visit has written: the encounter and every resource under it.
</ApiRef>

Read it back rather than trusting your own copy. What the repository holds is what every
other reader sees, and what the documents below are rendered from.

## Encounters hang from an episode

A visit is one attendance. An episode of care is the thread that runs through several of
them, such as a pregnancy, a course of chemotherapy or the management of a chronic condition,
and it is the unit a clinician thinks in.

<ApiRef method="GET" path="/api/v1/clinical/episodes-of-care" to="/rail-api/05-treat">
  The episodes this patient has open, and what each one is about. `GET /{id}` reads one, and `GET /{id}/visit-summary` returns everything hanging off it.
</ApiRef>

<ApiRef method="POST" path="/api/v1/clinical/episodes-of-care" to="/rail-api/05-treat">
  Open an episode, or attach this visit to one that is already running.
</ApiRef>

<Wire
  rows={[
    { call: "Attach before you open", does: "Check for an open episode for this condition first. A new episode per visit produces a record that cannot answer \"is this working?\" about anything.", keep: "episode_id" },
    { call: "The episode may not be yours", does: "It can have been opened at another facility. Attaching to it is what makes a shared record longitudinal rather than a pile of visits.", keep: "managing_facility" },
    { call: "Closing is a clinical statement", does: "An episode is closed because the condition was resolved or care was transferred, not because the last visit ended. A closed one refuses new attachments.", keep: "status" },
  ]}
/>

Episodes are also what make sessions legible to a payer. A course of dialysis authorised as a
series at [06 · Preauthorize](/rail/stops/Preauth) is the same thing this records clinically:
one episode, many encounters.

## What was requested, and who performs it

Ordering and prescribing have the same shape. Something is requested here, performed
somewhere else, and answered back against the request. Neither one needs an integration with
the performer, because both of you are already on the rail.

<Wire
  rows={[
    { call: "Orders", does: "Labs, imaging, procedures. Panels come back expanded into their parameters, and results return against the order rather than into a mailbox you poll.", keep: "order_id" },
    { call: "Prescriptions", does: "Routed to the pharmacy the patient chooses. That pharmacy pulls it from its own inbox, so nothing is carried in on paper.", keep: "prescription_id" },
    { call: "Both directions", does: "The same calls make you a performer as well as a requester. A facility that only posts orders has built half of it.", keep: "the inbox" },
  ]}
/>

  The full set: ordering across facilities, returning results against the expanded parameters,
  routed prescriptions, partial fills and substitution rules.

## Where the patient goes next

A referral carries the record rather than a request to start again, and it carries the
authorisation the patient already gave you, so they do not travel to the receiving facility
just to authenticate a second time for the same episode.

  Hub and spoke without building hub and spoke: sending patients and specimens, accepting
  inbound referrals, and how one authentication at the source facility stands at the
  destination.

## The documents generate themselves

This is the first thing all of that recording pays back. Every field a discharge summary or a
claim form contains was recorded above, so the rail can render those documents from the
clinical data instead of asking somebody to write them.

<ApiRef method="POST" path="/api/v1/visits/{visit_id}/documents/generate" to="/rail-api/05-treat">
  Generate the documents this claim requires, from what has already been recorded.
</ApiRef>

Where a document cannot be produced, the response names the clinical elements that are
missing rather than form fields. The fix is to record the fact while the encounter is still
open, instead of typing it into a template at submission.

An HMIS that records clinically is paperless the day it connects, without building a document
editor, a template engine or a PDF pipeline.

  Generating the required set, rendering HTML for the screen and PDF for a signature, and why a
  stored PDF should never be your source of truth.

## Read it back

Reading is the other half of contributing. A clinician who can see that a patient was
treated for the same thing three weeks ago at another facility makes a different decision, and
does not repeat an investigation the payer has already paid for.

  The cross-facility timeline this section used to name — `/api/v1/beneficiaries/{unique_patient_id}/timeline` —
  is not a registered route, and neither is anything else under `/api/v1/beneficiaries`. The closest
  live call is `GET /api/v1/clinical/episodes-of-care/{id}/visit-summary`, which returns everything
  under one episode. It is episode-scoped rather than member-scoped, so it is not a substitute:
  build the read-back around episodes until a member-wide route exists.

  The proof collected at [03 · Consent](/rail/stops/Consent) authorises reading and billing a
  member's cover. It does not, on its own, authorise publishing the encounter beyond this
  facility or reading what other facilities recorded. That is a separate purpose, collected
  through the same flow, and neither direction is retroactive. A record contributed without it
  is refused with `CLINICAL_CONSENT_MISSING` rather than written and withdrawn later.

## What breaks here

<CostTable
  rows={[
    {
      where: "Submit",
      symptom: "\"The claim was rejected for an invalid diagnosis code\"",
      cause: "A grouping or chapter heading was sent instead of a codable entity, or a code from a superseded release. Filter the picker on codable and refresh against the current version.",
    },
    {
      where: "Submit",
      symptom: "\"Every code is valid and it still bounced\"",
      cause: "The diagnoses were not linked to interventions. The payer assesses the pair, and an unlinked diagnosis is not assessed at all.",
    },
    {
      where: "Preauth",
      symptom: "\"The request came back saying the procedure is not indicated\"",
      cause: "The diagnosis does not support the intervention under the payer's clinical rules. The detail block names both codes and the rule, and usually the diagnosis is under-specified rather than wrong.",
    },
    {
      where: "Treat",
      symptom: "\"We record the diagnosis at discharge\"",
      cause: "By then the clinician has gone and the coder is working from notes. Every downstream check that could have been answered in the room becomes a rejection instead.",
    },
    {
      where: "Treat",
      symptom: "\"The bundle was rejected and we do not know which part\"",
      cause: "Read issues[], where each entry carries the index and the element. A transaction bundle is not partially written, so nothing landed.",
    },
  ]}
/>

### Errors

| HTTP | `error` | When |
|------|---------|------|
| 422 | `DIAGNOSIS_REQUIRED` | Something downstream needs a diagnosis and the visit has none. |
| 400 | `DIAGNOSIS_CODE_INVALID` | Not in the current release, or not a codable entity. |
| 422 | `DIAGNOSIS_NOT_LINKED` | A diagnosis with no intervention, or an intervention with no diagnosis. |
| 422 | `DIAGNOSIS_INTERVENTION_MISMATCH` | The pair is refused by the payer's clinical rules. |
| 409 | `PRIMARY_DIAGNOSIS_CONFLICT` | More than one diagnosis ranked primary. |
| 409 | `DIAGNOSIS_LOCKED` | Amended after the claim was submitted. |
| 400 | `CLINICAL_BUNDLE_INVALID` | The FHIR bundle failed validation. |
| 403 | `CLINICAL_CONSENT_MISSING` | No consent covering clinical sharing. |

  Every code recorded at this stop comes from the terminology service. How to fetch one, cache
  it by version, and find out when the release moves.

## Next

**Next:** [06 · Preauthorize](/rail/stops/Preauth)

<AgentPrompt>{`You are integrating an HMIS with the Savannah unified payer rail.

Task: implement stop 05 (Treat).

1. Populate the diagnosis picker from
   GET /api/v2/clinical/diagnoses?version=serving&q=<query>.
   Offer ONLY entries flagged codable. Never ship a hard-coded ICD-11 list.
2. POST /api/v2/visits/{visit_ref}/diagnoses for each diagnosis, with
   icd11_code, description, rank and the intervention_code it justifies.
   Exactly one rank: "primary" per visit.
3. POST /api/v1/visits/{visit_id}/clinical with a FHIR transaction bundle:
   Encounter, Condition (the same ICD-11 codes), Observation (LOINC-coded
   vitals and results), MedicationRequest where prescribing happened. Send it
   as the encounter progresses, not once at discharge.
4. Read what the record already holds before the consultation and show it to the
   clinician. There is no member-wide timeline route today; the closest is
   GET /api/v1/clinical/episodes-of-care/{id}/visit-summary, which is scoped to
   one episode.
5. Attach the visit to an open episode of care where one exists
   (GET /api/v1/clinical/episodes-of-care) rather than opening a new episode
   per visit.
6. Build the request/perform pair in BOTH directions: post orders and
   prescriptions, AND poll the inboxes
   (the order inbox is not built yet; GET /api/v1/prescriptions is).
   Return results against the order's expanded_parameters.
7. Generate required documents with
   POST /api/v1/visits/{visit_id}/documents/generate instead of authoring them.
   On status "incomplete", record the clinical elements named in missing[].

Rules:
- The diagnosis-to-intervention link is not optional metadata. An unlinked
  diagnosis is not assessed, and the claim is rejected for having none.
- Cache codes by the version you resolved against, and re-validate when the
  release moves. A retired code fails at assessment, not at recording.
- Withdrawal is allowed until the claim is submitted and refused after it.
  Corrections after submission are raised against the claim.
- Clinical sharing is a separate consent purpose from payer consent. Collect it
  at stop 03; do not assume the payer proof carries it.
- On a referral, send authorization_ref and open the receiving visit by ACCEPTING
  the referral. Opening a visit directly forces the patient to authenticate twice.
- The bundle is a transaction: on failure nothing was written. Read issues[] and
  resend the whole bundle.`}</AgentPrompt>
