Back to Blog

OMOP Concept Mapping API: A Practical Developer Guide

Dr. Lisa MartinezDr. Lisa Martinez
July 28, 2026
16 min read
OMOP Concept Mapping API: A Practical Developer Guide

You can stare at a source table full of SNOMED, ICD-10, or local clinic codes and still not know whether your OMOP target will survive the next vocabulary refresh. That's the problem with an OMOP concept mapping API in production. The hard part isn't finding a concept once, it's making the same mapping decision again, proving why it was chosen, and keeping that decision stable when a clinician, auditor, or downstream analyst comes back months later.

Why OMOP Mapping Breaks Without a Reproducible Workflow

Every ETL team has seen this pattern. A developer grabs a source code, runs a lookup, accepts the first plausible target, and ships the mapping as if vocabulary work were a one-time event. It feels fine until a new release lands, or a domain expert says the target is clinically wrong, or an analyst asks why a seed concept exploded into too many descendants. The failure usually starts with over-inclusion from broad seed concepts and ends with missing provenance in SOURCE_TO_CONCEPT_MAP, which makes the result hard to defend later.

The right mental model is simple. Resolve the source code and vocabulary, prefer a deterministic match when one exists, then fall back to server-side Maps to logic only when you need traversal. That ordering matters because the mapping is not just search, it's a reproducibility decision.

Practical rule: treat every target as a versioned decision, not a lookup result.

The FHIR-to-OMOP guidance is explicit about this kind of discipline, it says to document each coding element, choose the primary code by prioritization rules, and map to the closest parent concept when a direct standard concept isn't available. The OHDSI conversion guidance also requires loading source codes, having clinicians or domain experts review suggested mappings, and exporting only after review into SOURCE_TO_CONCEPT_MAP (HL7 FHIR to OMOP coding mappings). That's the bar if you want an ETL that holds up under review.

Why release pinning is part of the mapping itself

A mapping without an explicit vocabulary release is only half a record. If ATHENA changes, the same source code can resolve differently, and a past ETL run becomes hard to reconstruct. Pin the release version the moment you freeze the target concept, then keep that release ID beside the target, the reviewer, and the justification snippet. That turns a lookup into an audit trail.

The OMOP vocabulary ecosystem now exposes 11 million+ standardized OMOP concepts across SNOMED CT, ICD-10, LOINC, RxNorm, and 100+ terminologies through REST-based access, which removes the old excuse that vocabulary work must happen inside a local database with quarterly maintenance windows (OMOP vocabulary ecosystem overview). That shift matters because reproducibility gets easier when the vocabulary surface is stable, queryable, and version-aware.

Authenticating and Making Your First Concept Lookup

A first lookup should prove the workflow is reproducible before it proves the vocabulary is searchable. Get an API key from the dashboard, decide whether you are calling the REST API or the FHIR surface, and keep the same key management approach across both. The REST API uses a Bearer token in the Authorization header, and the same key works across the REST and FHIR surfaces. That keeps a mapping pipeline easier to audit, especially when one service resolves concepts and another service validates FHIR terminology calls.

Screenshot from https://omophub.com

A minimal REST lookup

A first lookup should prove three things, authentication works, the API returns the expected concept fields, and the round trip is fast enough for interactive use. The quickstart guide says you only need an API key and a programming environment, then you can install the SDK with pip install omophub and authenticate by setting OMOPHUB_API_KEY or passing the key into the client (quickstart guide).

curl -X POST "https://api.omophub.com/v1/fhir/resolve" \
  -H "Authorization: Bearer oh_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"system":"http://snomed.info/sct","code":"44054006","resource_type":"Condition"}'

That call shape matters because the resolver returns the standard concept and CDM target table in one shot, which is the information an ETL step needs before it writes downstream records. The introduction also lists a sub-50ms typical response time, which is concrete enough to weigh against precomputing lookups or calling the service inline (quickstart guide).

The Python SDK path

After pip install omophub, set the environment variable and use the client directly. That keeps credentials out of code while still making local testing straightforward.

import os
from omophub import Client

client = Client(api_key=os.environ["OMOPHUB_API_KEY"])
result = client.fhir.resolve({
    "system": "http://snomed.info/sct",
    "code": "44054006",
    "resource_type": "Condition"
})
print(result)

For Spring Security clients like HAPI FHIR or EHRbase, the FHIR service also accepts OAuth2 client_credentials, so the same vocabulary service can fit different integration styles without changing the mapping logic. The first response should include the fields you need for downstream writes, especially the concept name, domain, and vocabulary context. If you want a fuller walkthrough of the request shapes and client setup, the OMOPHub's vocabulary API guide is the reference I would keep close while wiring the pipeline.

Searching the Vocabulary by Meaning, Not Just Keywords

A clinician will not always say “myocardial infarction.” They may say heart attack, and if the lookup layer depends on exact keywords, the pipeline will miss the concept or hand the work off to a manual reviewer. Meaning-based search belongs at the front of the workflow because the person entering the term often does not know the canonical vocabulary yet.

A comparison graphic showing keyword search versus meaning-based search for vocabulary, highlighting better results with semantic search.

Use the search mode that matches the task

Exact keyword search still works when the source string is already close to the canonical term. Fuzzy search helps when spelling or punctuation drifts. Semantic search is the better fit when the phrasing is human, not terminological. The MCP tool semantic_search uses neural embeddings and supports three similarity algorithms, which makes it useful for bridging clinical language and vocabulary language (MCP tools reference).

The practical examples are easy to read. heart attack returns Myocardial infarction, and high blood sugar returns Hyperglycemia. That is the difference between search and mapping. Search identifies the likely concept, but the mapping step still has to pin the release and record the review trail. For a closer look at why semantic retrieval improves vocabulary work, see OMOP semantic search for clinical vocabulary matching.

Keep autocomplete and faceting in the right place

Autocomplete belongs in user interfaces and curation workbenches, not in batch ETL. Faceted search helps when you need to narrow by domain or vocabulary, especially during phenotype authoring or manual review. Both help people choose better candidates, but neither replaces an auditable mapping decision.

The tool constraint matters too. semantic_search accepts exactly one of concept_id, concept_name, or query (MCP tools reference). That rule prevents sloppy calls from drifting into ambiguous search behavior. If your team builds a curation UI, keep the search step separate from the acceptance step so reviewers can see what matched, what was rejected, and why.

The concept lookup tool at OMOPHub for designing ETL workflows is a useful reference point for designers and ETL developers alike.

Building Cross-Vocabulary Mappings the Auditable Way

A mapping pipeline should start with a single source code, a single source vocabulary, and a decision tree that prefers the most exact outcome available. In practice, that means identifying the source, resolving deterministic matches first, using server-side Maps to logic next, and then freezing the target against the exact vocabulary release so the result can be reproduced later.

Single, batch, and CodeableConcept flows

The Get Concept Mappings API is the retrieval layer for that workflow. It returns mappings from a source concept to equivalent or related concepts in other vocabulary systems, and the same family of terminology operations also supports FHIR-conformant integrations across R4, R4B, R5, and R6 (Get Concept Mappings API). In ETL work, that matters because the same service can serve a batch mapping job, a curation review screen, and a FHIR terminology endpoint without changing the mapping rules underneath.

VariantBest forInput shapeThroughput
SingleOne-off ETL checksOne concept at a timeLowest overhead
BatchSource table processingMultiple concepts in one requestBest for repetitive jobs
CodeableConceptFHIR-oriented integrationsFull FHIR code structureBest for interoperable payloads

A concrete example makes the call shape easier to reason about. Suppose a source feed carries a SNOMED code for diabetes and the ETL needs to write a standard OMOP target into CONDITION_OCCURRENCE. A POST /v1/fhir/resolve request can return the standard concept, domain, mapping type, and CDM target table in one response, so the pipeline does not have to infer the destination from an intermediate search result. For the common SNOMED example 44054006, that response points to the OMOP standard concept for diabetes mellitus type 2 and the CONDITION_OCCURRENCE table. That is the kind of output an ETL can persist directly, while still leaving room for review if the source vocabulary has multiple plausible matches.

Why release selection belongs in the request

OMOPHub's mapping API lets you select a specific release, and if you omit it, the service defaults to the latest version (concept mapping workflow article). That default is fine for exploration, but production mapping needs a pinned release so the same source code resolves the same way after vocabulary updates. I would write the release version into the mapping record rather than let the lookup drift with whatever is current at runtime.

Resolve candidates once, then make the final choice once per release, not once per run.

The endpoint returning all equivalent or related mappings is useful because it gives a reviewer the full candidate set instead of a black box answer. In a real pipeline, the reviewer can inspect the candidates, reject the ones that do not fit the phenotype or table rule, and then the ETL can store one chosen target with the release metadata attached. That is the difference between a convenience lookup and an auditable mapping record.

What to log with each resolved mapping

Keep the record tight and explicit. Capture the source code, source vocabulary, chosen target concept, vocabulary release, mapping type, reviewer, and timestamp. If the mapping came from a batch request, keep the request identifier too. The value is not just that the mapping exists, it is that someone can reconstruct why it exists when the source term changes or a clinical reviewer asks for the rationale months later.

Traversing Hierarchies and Expanding Concept Sets

Phenotype work rarely ends at one concept. A real cohort definition usually needs a closure over the hierarchy, plus a few non-hierarchical relationships that catch codes a tree walk would miss. The safest expansion strategy starts narrow, then widens only where the phenotype rules justify it.

Walk ancestors and descendants with intent

Ancestor and descendant traversal helps you decide whether a concept belongs in a broader family or whether it's too general to use as a seed. If the source term is diabetes-related, you don't want to blindly swallow every nearby metabolic code. You want a controlled expansion that matches the clinical question, then serialize that result into a concept set expression JSON your downstream tools can reuse.

The hierarchy API is useful because it lets you inspect the shape of the vocabulary before you expand it into production logic. A concept set built from a small seed can become defensible if each descendant is there for a reason, not because the default traversal was left wide open (concept hierarchy guide).

Limit the relationship types

Hierarchical descendants are only part of the story. Non-hierarchical relationships like Has finding site or Has causative agent can surface relevant concepts that a pure tree walk misses. That's especially important when phenotype logic cares about manifestations, causes, or related clinical findings rather than a single concept lineage.

A cautious diabetes phenotype might begin with a narrow seed and then expand only across relationships that preserve clinical meaning. The point is to capture the relevant codes without dragging in unrelated conditions that happen to live nearby in the vocabulary graph. Over-inclusion here creates noisy cohorts, and once the concept set is embedded in ETL, that noise spreads quickly.

Practical tip: review the expanded set in the same vocabulary release you'll use in production, not in a later version.

That last step matters because concept set definition and release pinning are inseparable. If you expand against one release and execute against another, the concept set can drift even when your code hasn't changed.

Release Pinning, Provenance, and Clinical Review

The first thing I check in a production mapping pipeline is whether the target vocabulary release is pinned. If ATHENA refreshes underneath an unpinned workflow, the same source code can resolve to a different concept on the next run. At that point, the problem is not search quality, it is reproducibility. A mapping row without release metadata, provenance, and review history only reflects a momentary decision.

Build an audit row that survives refreshes

A durable mapping record should carry the source code, target concept, vocabulary release, reviewer ID, review timestamp, and a short justification note. If the code crossed a domain boundary, that reviewer step matters even more. The OHDSI conversion guidance says to load source codes, have clinicians or domain experts review and update suggested mappings, and export only after review into SOURCE_TO_CONCEPT_MAP.

That is operational control, not paperwork. It gives the next analyst a way to explain why a code landed in CONDITION_OCCURRENCE or another target domain without digging through a ticket queue or guessing from old ETL notes. It also makes drift visible when a later vocabulary refresh changes the candidate set.

Prioritize the primary code deliberately

The same guidance says to document each coding element and choose the primary code by prioritization rules. That matters for multi-coded source payloads, where a pipeline can easily grab the first field in the JSON and treat it as authoritative. I prefer to make that choice explicit in the mapping record so the selection rule is visible during review.

If a mapping came from Maps to rather than a deterministic match, mark it that way in the record. If a clinician reviewed a broad seed expansion, capture the approval context and the release used for that review. These fields do more than satisfy audit requirements. They show which mappings are stable, which ones depend on interpretation, and where a later ETL run needs extra scrutiny.

Keep the review loop short and explicit

The cleanest teams handle mapping review the same way they handle code review. A developer proposes the target, a clinician checks the clinical meaning, and the ETL writes the final record only after both the target and the vocabulary release are fixed. That keeps provenance attached to the decision instead of being reconstructed after the fact.

I have seen pipelines fail because the review step was treated as a one-time approval instead of a record that needs to survive refreshes. Once a release changes, you want to know which mappings were accepted under the old vocabulary, which ones need re-review, and which ones can be carried forward without debate.

Performance, Compliance, and Common Pitfalls in Production

A mapping API can be fast and still slow down your pipeline if you use it badly. The practical performance play is to batch where you can, cache deterministic lookups for the lifetime of a release, and reserve semantic search for the ambiguous tail of your code distribution. That keeps the expensive work where it belongs, on the hard cases.

An infographic titled Performance, Compliance, and Common Pitfalls in Production, outlining key strategies for building reliable software systems.

Keep the request pattern lean

The mapping workflow supports batch requests, and the product brief calls out up to 100 per request for concept mapping work. Use that for table-driven ETL, not for interactive troubleshooting. For ambiguous entries, push only the unresolved tail into semantic search, then hand the result back into the deterministic mapping path.

A useful operational habit is to cache exact matches for the entire vocabulary release. Once a source code resolves deterministically and the release is fixed, there's little value in recomputing that same answer on every run. That also reduces noise in logs and makes failures easier to isolate.

Stay inside the compliance boundary

OMOPHub is a vocabulary lookup service, so the request payload should stay at the level of terminology codes and concept IDs. No patient identifiers, clinical notes, or other Protected Health Information should flow through it. Access is via per-user, revocable, scopeable Bearer API keys over HTTPS, and the FHIR service also accepts OAuth2 client_credentials for Spring Security clients like HAPI FHIR and EHRbase.

That boundary makes the service easier to place in real enterprise architectures. You still need your own retention and access policies around audit logs, but the API itself should stay focused on terminology, not patient data.

Avoid the failures that waste the most time

The most common mistakes are predictable. Teams map without release pinning, trust Maps to blindly, skip clinical review on broad expansions, or forget that the same key can hit R4, R4B, R5, and R6 on the same endpoint. None of those problems are technically hard to prevent, but they become expensive when they sit inside a nightly ETL.

For teams deciding whether to self-host or use a service, the trade-off is operational rather than conceptual. Self-hosting still fits air-gapped environments, custom proprietary vocabulary extensions, or strict rules against external calls. A hybrid pattern, develop against OMOPHub and cache results for local production, can give you both speed in development and control in deployment.

A short checklist for production teams

  • Batch the routine work: use batch requests for repetitive mapping jobs, then isolate exceptions for manual review.
  • Pin every release: write the vocabulary version into the mapping record and into your ETL metadata.
  • Review the broad seeds: let clinicians inspect expansions that could over-include unrelated concepts.
  • Separate lookup from approval: keep search, candidate selection, and final export as distinct steps.
  • Treat the API key like an app credential: store it in a secrets manager and rotate it on a schedule that fits your controls.

If you want a single place to start, the docs at OMOPHub cover the REST, FHIR, SDK, and MCP surfaces in one workflow, which makes it easier to wire reproducible concept mapping into ETL instead of treating it like an ad hoc lookup step.

Share: