# The whole surface

  Every coded thing on the rail resolves here: what a code means, whether it is still valid, what it
  belongs to, what it maps to, and what it costs. One service answers all seven kinds of question.

This page lists every operation, grouped by the question it answers, with a link into
[the Terminology API reference](/terminology-api) where each one can be read in full. Four of the
groups are taught in their own right, so if you have a task rather than a survey in mind, start
there.

- [Fetching a coded list](/rail/reference/Value-Sets), for populating a dropdown, syncing on a
  schedule, or exporting a list as a spreadsheet for a human to review.
- [Walking a concept tree](/rail/reference/Terminology-Walking-The-Tree), because large vocabularies
  are hierarchies and the list you are handed often starts partway down one.
- [Validating a code](/rail/reference/Terminology-Validating-Codes), checking a code at the
  boundary where it enters your system rather than at submission.
- [Pinning to a release](/rail/reference/Terminology-Pinning-Versions), covering what
  `version=serving` resolves to and how to stop an upstream vocabulary change from becoming an
  incident on your side.
- [Translating between vocabularies](/rail/reference/Terminology-Concept-Maps), for coding a
  diagnosis once when one payer wants ICD-11 and another is still on ICD-10.
- [Getting the data you need](/rail/reference/Terminology-Getting-Data), covering JSON, FHIR, CSV,
  Excel or a bare code list, in and out, and which shape to pick.

  Authentication is a token rather than a header. The service reads the realm from the token itself,
  so there is no variant or tenant header to guess at. What a call returns is scoped to the
  organisation that token belongs to.

  Anonymous is a real access level rather than a broken one. Discovery and search answer without any
  credential, and an unauthenticated caller sees only what is published publicly. A list that comes
  back emptier than you expected is usually a question of scope rather than absence.

## Discovery: what exists, and who you are

[Open the group in the reference →](/terminology-api/discovery)

<Wire
  rows={[
    { call: "GET /metadata", does: "What this server declares it supports. Make it the first call when wiring any FHIR terminology client.", keep: "the capability statement" },
    { call: "GET /orgs/current/", does: "Echoes the active organisation for this token. Run it the moment a list comes back emptier than expected, because the cause is almost always scope.", keep: "the active org" },
    { call: "GET /orgs/accessible/", does: "Every organisation this token can read, and how to switch between them.", keep: "org codes" },
    { call: "GET /code-systems/", does: "The catalogue. Authenticated callers see their organisation's systems; anonymous callers see only public ones.", keep: "short_code, id" },
    { call: "GET /code-systems/{system}/", does: "Detail for one system. Accepts either the numeric id or the short code, case-insensitively.", keep: "canonical url" },
    { call: "GET /code-systems/{system}/versions/", does: "The version ladder plus the pin: every version newest-first flagged is_serving, alongside pin_mode and pinned_version. This is how you learn what ?version=serving resolves to.", keep: "version_id, is_serving, pin_mode" },
    { call: "GET /code-systems/{system}/used-by/", does: "Which value sets and concept maps bind to this system. Check it before assuming a system can be retired.", keep: "—" },
  ]}
/>

## Concepts: reading one, and walking the tree

[Open the group in the reference →](/terminology-api/concepts) · taught in [Walking a concept tree](/rail/reference/Terminology-Walking-The-Tree)

<Wire
  rows={[
    { call: "GET /concepts/?system=", does: "The membership of a system, paged. It is version-aware, so ?version=serving pins to the release the owner is serving, and a version_id reads exactly what was frozen there.", keep: "code, display" },
    { call: "GET /concepts/{id}/", does: "One concept, with the identity a detail page needs: uri, owning system, and the version it was introduced in.", keep: "uri" },
    { call: "GET /concepts/roots/?system=", does: "The top of the tree. Start here for lazy rendering, then walk children.", keep: "root codes" },
    { call: "GET /concepts/{id}/children/ · /parents/", does: "One level in either direction.", keep: "—" },
    { call: "GET /concepts/{id}/descendants/ · /ancestors/", does: "Transitive, served from a closure table rather than computed by you.", keep: "—" },
    { call: "GET /concepts/{id}/value-sets/", does: "Reverse membership, meaning which value sets expand to include this concept.", keep: "—" },
    { call: "GET /concept-revisions/?concept=", does: "Append-only revisions for one concept, each carrying the full child collections, so a revision is a faithful 'before' for a diff.", keep: "—" },
  ]}
/>

  Ancestors and descendants are served from a closure table. Fetching children repeatedly and
  assembling the tree in the client is slower, and it drifts the moment the vocabulary is
  re-parented.

## FHIR operations: code in, answer out

[Open the group in the reference →](/terminology-api/fhir-operations) · taught in [Validating a code](/rail/reference/Terminology-Validating-Codes)

All of these are `GET`, all return a FHIR `Parameters` resource, and all are version-aware.

<Wire
  rows={[
    { call: "$lookup", does: "Resolve a code's display, definition, designations and properties.", keep: "display" },
    { call: "$validate-code (code system)", does: "Does this code exist, and is it active?", keep: "result" },
    { call: "$validate-code (value set)", does: "Is this code a member of this value set? The binding check for a form field.", keep: "result" },
    { call: "$subsumes", does: "Relationship between two codes: equivalent, subsumes, subsumed-by, or not-subsumed.", keep: "outcome" },
    { call: "$find-matches", does: "Rank concepts by free-text match within one system, for autocompletion against a known vocabulary.", keep: "matches" },
    { call: "$translate (concept map)", does: "Source code to target mapping, one match per target. This is the ICD-11 to ICD-10 crosswalk and anything like it. It is grouped under concept maps below, because using it well is mostly about reading the equivalence.", keep: "the target code" },
  ]}
/>

  `$validate-code` always answers `200`. Whether the code is valid is in the `result` parameter of the
  body, not in the status. An integration that branches on the status code will treat every invalid
  code as accepted.

## Value sets: membership, and why

[Open the group in the reference →](/terminology-api/value-sets) · taught in [Fetching a coded list](/rail/reference/Value-Sets)

<Wire
  rows={[
    { call: "GET /value-sets/{short code}/expansion/", does: "The member list. Same response shape whether it was precomputed or resolved on the spot.", keep: "codes" },
    { call: "GET /value-sets/{short code}/staleness/", does: "Whether the stored expansion still reflects its source systems. Poll this rather than re-expanding blindly.", keep: "stale or not" },
    { call: "GET /value-sets/{short code}/compose/", does: "The include and exclude rules the expansion was built from, which is the answer to 'why is this code in here?'", keep: "—" },
    { call: "GET /value-sets/{short code}/used-in/", does: "Where this value set is bound.", keep: "—" },
  ]}
/>

## Versioned reads: pinning, and auditing

[Open the group in the reference →](/terminology-api/versioned-reads) · taught in [Pinning to a release](/rail/reference/Terminology-Pinning-Versions)

Once you are live, this is the group you lean on hardest, because it is how you stop a vocabulary
change from becoming an incident.

<BuildSequence
  steps={[
    {
      do: "Pin with ?version=serving",
      detail:
        "A frozen read of whatever the artefact currently resolves to, without having to look up its number first. This is the default an integration should use.",
    },
    {
      do: "Pin harder with a version_id",
      detail:
        "Exactly what was frozen at that release, and only released versions are honoured. A version that held ten concepts keeps returning ten however many the working copy has since gained. That is the point, and it is why a pinned read is cacheable indefinitely.",
    },
    {
      do: "Diff with /changed/",
      detail:
        "The working copy against the serving version. A modified row carries both the before and after objects, so you can show what actually changed rather than only that something did.",
    },
    {
      do: "Read the ladder with /versions/",
      detail:
        "Every version newest-first, flagged is_serving, with pin_mode and pinned_version. This is what tells you whether serving is following the newest release or an owner's deliberate pin.",
    },
    {
      do: "Log the version alongside the value",
      detail:
        "Whatever you store a coded value on, store which version you read it at. When a code stops being accepted months later, that record is what lets you answer the question instead of guessing at it.",
    },
  ]}
/>

## Benefits and rates

[Open the group in the reference →](/terminology-api/benefits-and-rates) · taught in [What a cover pays for](/rail/guides/Benefit-Tree)

Two groups you will meet on the rail rather than in a general terminology client.

Benefits resolve in layers. Library → scheme → panel, each overlaying sparse overrides on the one
beneath. Resolve one node, or take the whole set in a single pass rather than making a request per
concept.

<Wire
  rows={[
    { call: "GET /code-systems/{scheme}/effective/{node}/", does: "One node resolved under a scheme, with a ?version= read overlaying the profile as it stood at that release.", keep: "the resolved node" },
    { call: "GET /code-systems/{scheme}/effective/", does: "The whole set in one pass. Prefer this to N single-node calls.", keep: "the resolved set" },
    { call: "GET /panels/{panel}/effective/", does: "The same resolution with the panel layer on top.", keep: "the resolved set" },
    { call: "GET /panels/{panel}/$lookup/", does: "Panels carry the same FHIR operation set as code systems.", keep: "—" },
  ]}
/>

Rates are release-gated. Only a released version's lines are payable, so an agreement carrying
nothing but an open draft resolves to no price at all. That is a correct answer rather than a
missing one.

<Wire
  rows={[
    { call: "GET /rates/effective/", does: "One scheme, one node, returning the full library → scheme → panel → provider envelope.", keep: "the effective rate" },
    { call: "POST /rates/effective/lookup/", does: "Many schemes and nodes in one round-trip. A scheme the facility is not empanelled for simply does not appear.", keep: "the envelope per node" },
  ]}
/>

## Concept maps: code in, other vocabulary out

[Open the group in the reference →](/terminology-api/concept-maps) · taught in [Translating between vocabularies](/rail/reference/Terminology-Concept-Maps)

<Wire
  rows={[
    { call: "GET /concept-maps/", does: "Find a map by source and target system, by canonical_url, or by short code. Public for published maps.", keep: "the map id" },
    { call: "GET /concept-maps/{short code}/$translate/?code=", does: "One code in, targets out, each with an equivalence. This is the crosswalk call.", keep: "the target code" },
    { call: "GET /concept-maps/{short code}/entries/", does: "Every row, filterable by equivalence and by whether it is mapped. This is where a positive no-mapping declaration is visible, since $translate hides those.", keep: "no_map, no_map_reason" },
    { call: "GET /concept-maps/{short code}/concept-map.json", does: "The whole map as FHIR, for loading a crosswalk locally rather than calling per code.", keep: "the resource" },
  ]}
/>

## Getting the data out

[Open the group in the reference →](/terminology-api/getting-the-data-out) · taught in [Getting the data you need](/rail/reference/Terminology-Getting-Data)

<Wire
  rows={[
    { call: "GET /code-systems/{short code}/export/", does: "One system as FHIR R4, synchronously. It is bounded, so above the inline limit it answers 413 and names the release job. ?_summary=true is the cheap header-only read.", keep: "the resource" },
    { call: "POST /release-jobs/", does: "The asynchronous export that hands you a file: FHIR, CSV, XLSX or bare codes, in FULL, SNAPSHOT or DELTA mode. DELTA is how a local copy updates incrementally.", keep: "the job id" },
    { call: "POST /release-jobs/preview/", does: "Same body, but a dry run. Counts and sample rows, with nothing stored.", keep: "row_count" },
    { call: "GET /release-jobs/{id}/ · /download/", does: "Poll (public, no token) then download (token, redirects to the live presigned URL).", keep: "status" },
  ]}
/>

## Search

[Open the group in the reference →](/terminology-api/search)

<Wire
  rows={[
    { call: "GET /search/", does: "Across concepts, systems, value sets and maps. Anonymous callers are allowed.", keep: "hits with their path" },
    { call: "GET /search/typeahead/", does: "Concept-only and latency-shaped for an autocomplete box. Requires a token, unlike the general search.", keep: "hits" },
  ]}
/>

  `POST /bulk/export/code-system/{short code}/` queues a CSV and answers `202` with a confirmation
  and no job id, so there is nothing to poll and no link to follow. Where you need the file back,
  use
  [a release job](/rail/reference/Terminology-Getting-Data#for-a-person--csv-excel-or-a-bare-code-list).

## What to build against

<BuildSequence
  steps={[
    { do: "Read serving rather than latest", detail: "Pin every runtime read to the serving version so an unreleased draft can never reach a patient-facing screen." },
    { do: "Validate rather than assume", detail: "Use $validate-code at the boundary where a code enters your system, and read the result parameter rather than the status." },
    { do: "Poll staleness, do not re-expand", detail: "Re-expanding a large value set on a schedule is expensive and usually unnecessary." },
    { do: "Log the version with the value", detail: "When a code stops being accepted, the first question is which version you were reading. Store it so you can answer that." },
  ]}
/>

**Next:** [Value sets and code systems](/rail/reference/Value-Sets) ·
[Error dictionary](/rail/reference/Errors)
