Layman manual
The read API and the seven import CLIs are shipped and in use. This is
the current operator + integrator surface.
Platform operators and developers of other PDHC services (plan.pdhc,
rosetta.pdhc, cdr.pdhc, forms.pdhc, etc.) that need to resolve
canonical terminology URIs.
End users never reach termbank.pdhc directly — they interact through
plan.pdhc's curation UI, which browses termbank.pdhc on their behalf.
A bulk canonical terminology store. It imports upstream vocabularies
as-is and serves them read-only over HTTP. It owns the canonical URI
namespace https://termbank.pdhc.se/CodeSystem/<system>/<code> — no
other service mints these URIs. plan.pdhc mirrors the ones it curates,
rosetta.pdhc stores mappings that point to them.
The read API is public (no auth, Rule 24). Every mutating HTTP
method returns 405 — the only way data changes is the import CLIs,
run by an operator.
# FHIR R5 CodeSystem $lookup — the primary, spec-shaped operation
curl 'https://termbank.pdhc.se/fhir/CodeSystem/$lookup?system=loinc&code=4548-4'
# Same, asking for the Swedish display on the top line
curl 'https://termbank.pdhc.se/fhir/CodeSystem/$lookup?system=snomed&code=73211009&displayLanguage=sv'
# Convenience shortcut: look up by system + code in the path
curl https://termbank.pdhc.se/CodeSystem/loinc/4548-4
# Look up by canonical URI (query parameter, not a path segment)
curl 'https://termbank.pdhc.se/Concept?uri=https://termbank.pdhc.se/CodeSystem/loinc/4548-4'
# Fuzzy search across display + designations
curl 'https://termbank.pdhc.se/search?q=HbA1c&system=loinc&limit=20'
# CapabilityStatement (what the service advertises)
curl https://termbank.pdhc.se/fhir/metadata
# Health (DB reachability + per-source version/staleness)
curl https://termbank.pdhc.se/health
$lookup, /CodeSystem/<system>/<code> and /Concept?uri= all return
the same FHIR R5 Parameters resource (name, version, display,
property entries, designation entries). /search returns a plain
JSON list (not a FHIR Bundle). Errors come back as FHIR
OperationOutcome with an appropriate HTTP status (400 missing args,
404 not found, 405 mutation attempt).
$lookup via POST$lookup also accepts POST with a FHIR Parameters body (the URL-escaped
/fhir/CodeSystem/%24lookup form works too). This is a read, not a
mutation, so it is exempt from the 405 rule:
curl -X POST 'https://termbank.pdhc.se/fhir/CodeSystem/$lookup' \
-H 'content-type: application/json' \
-d '{"resourceType":"Parameters","parameter":[
{"name":"system","valueUri":"loinc"},
{"name":"code","valueCode":"4548-4"}]}'
displayLanguage$lookup, /CodeSystem/<system>/<code> and /Concept?uri= accept an
optional displayLanguage (e.g. sv). When supplied, the top-line
display is replaced with that language's preferred designation if
one exists (then fsn, then any designation in that language, then the
default display). The full designation list still carries every
language.
q — required. Ranked across Concept.display and designation valuessystem — optional. Repeat it (?system=loinc&system=snomed) or pass?system=loinc,snomed) to restrict.limit — optional, default 20, capped at 200.displayLanguage — optional.System (system=) |
Importer | Source |
|---|---|---|
loinc |
import_loinc.py |
LOINC release table |
snomed |
import_snomed.py |
SNOMED CT Managed Service SE |
icd10 |
import_icd10.py |
ICD-10-SE (Socialstyrelsen) |
atc |
import_atc.py |
ATC (Läkemedelsverket / SeNSL) |
kva |
import_kva.py |
KVA — medical (KMA) + surgical (KKA) procedures |
socialstyrelsen |
import_sosstyr.py |
Socialstyrelsen termbank (full XML) |
icf |
import_icf.py |
ICF (Socialstyrelsen) |
There is no ICD-11 importer.
All imports are CLI-only. Every importer requires --source-url and
--version (source URL is recorded for provenance even when a local
file is used). Re-running with an already-imported --version is a
no-op; a new --version updates concepts in place while preserving each
canonical_uri. Optional on every importer: --operator (defaults to
$USER@$HOST) and --batch-size (default 2000).
Run from the repo root with the venv active:
# LOINC — requires --local-file (the LoincTable CSV)
python scripts/import_loinc.py \
--source-url https://loinc.org/file/loinc-2.82 \
--version 2.82 \
--local-file ./Loinc_2.82/LoincTable/Loinc.csv
# SNOMED CT SE — requires --release-dir (the RF2 release folder)
python scripts/import_snomed.py \
--source-url https://mlds.ihtsdotools.org/.../SE \
--version SE1000052_20251130 \
--release-dir ./SnomedCT_ManagedServiceSE_PRODUCTION_SE1000052_20251130T120000Z
# ICD-10-SE — requires --local-file (the TSV)
python scripts/import_icd10.py \
--source-url https://www.socialstyrelsen.se/.../icd-10-se \
--version 2024 \
--local-file ./icd-10-se.tsv
# ATC — requires --local-file (the SeNSL ATC XML)
python scripts/import_atc.py \
--source-url https://www.lakemedelsverket.se/sv/sensl \
--version v2 \
--local-file 'sensl-v2/codesystems/atc-code.xml'
# KVA — requires --kma-file and/or --kka-file (at least one)
python scripts/import_kva.py \
--source-url https://www.socialstyrelsen.se/.../kva \
--version 2026 \
--kma-file ./kva-medicinska-atgarder-kma.tsv \
--kka-file ./kva-kirurgiska-atgarder-kka.tsv
# Socialstyrelsen termbank — --local-file is optional (downloads otherwise)
python scripts/import_sosstyr.py \
--source-url https://www.socialstyrelsen.se/.../socialstyrelsenstermbank_komplett.xml \
--version 4.3.6-2025-12-17
# ICF — requires --local-file (the TSV)
python scripts/import_icf.py \
--source-url https://www.socialstyrelsen.se/.../icf \
--version 2024 \
--local-file ./icf.tsv
There are no --release-csv / --release-tsv flags — the single-file
importers all use --local-file, SNOMED uses --release-dir, and KVA
uses its two --kma-file / --kka-file inputs.
GET /health returns 200 with status: "ok" when the database is
reachable, 503 with status: "degraded" when it is not. It also lists
every imported source with its version, concept count, the pinned
<SOURCE>_VERSION env value (if set), and a stale flag when the two
disagree — so you can spot when the running data is behind the pinned
release.