> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omophub.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK - FHIR Resolver for OMOP concepts

> Resolve FHIR Coding and CodeableConcept values to OMOP standard concepts from the OMOPHub Python SDK with one call - ideal for Python-based ETL pipelines.

## Resolve a Single FHIR Coding

Translate a FHIR `Coding` (system URI + code) to an OMOP standard concept and CDM target table:

```python theme={null}
result = client.fhir.resolve(
    system="http://snomed.info/sct",
    code="44054006",
    resource_type="Condition",
)
res = result["resolution"]
print(res["standard_concept"]["concept_name"])  # "Type 2 diabetes mellitus"
print(res["target_table"])                       # "condition_occurrence"
print(res["mapping_type"])                       # "direct"
```

## Resolve a Non-Standard Code (Maps to Traversal)

ICD-10-CM and other classification codes are automatically mapped to their standard equivalents:

```python theme={null}
result = client.fhir.resolve(
    system="http://hl7.org/fhir/sid/icd-10-cm",
    code="E11.9",
)
res = result["resolution"]
print(res["source_concept"]["vocabulary_id"])    # "ICD10CM"
print(res["standard_concept"]["vocabulary_id"])  # "SNOMED"
print(res["mapping_type"])                       # "mapped"
print(res["relationship_id"])                    # "Maps to"
print(res["target_table"])                       # "condition_occurrence"
```

## Text-Only Resolution (Semantic Search Fallback)

When no structured code is available, pass the display text for semantic search:

```python theme={null}
result = client.fhir.resolve(
    display="Blood Sugar",
    resource_type="Observation",
)
res = result["resolution"]
print(res["standard_concept"]["concept_name"])  # "Glucose [Mass/volume] in Blood"
print(res["mapping_type"])                       # "semantic_match"
print(res["similarity_score"])                   # 0.91
print(res["target_table"])                       # "measurement"
```

## Skip URI Resolution with vocabulary\_id

If you already know the OMOP vocabulary, bypass the URI lookup:

```python theme={null}
result = client.fhir.resolve(
    vocabulary_id="ICD10CM",
    code="E11.9",
)
```

## Include Phoebe Recommendations

Get related concepts for phenotype development alongside the resolution:

```python theme={null}
result = client.fhir.resolve(
    system="http://snomed.info/sct",
    code="44054006",
    include_recommendations=True,
    recommendations_limit=5,
)
for rec in result["resolution"]["recommendations"]:
    print(f"  {rec['concept_name']} ({rec['domain_id']}) via {rec['relationship_id']}")
    # "Hyperglycemia (Condition) via Has finding"
    # "Diabetic retinopathy (Condition) via Associated finding"
```

## Include Mapping Quality Signal

Assess whether a resolution needs manual review:

```python theme={null}
result = client.fhir.resolve(
    system="http://snomed.info/sct",
    code="44054006",
    include_quality=True,
)
print(result["resolution"]["mapping_quality"])  # "high", "medium", "low", or "manual_review"
```

## Batch Resolution

Resolve up to 100 codings in a single call. Failed items are reported inline:

```python theme={null}
result = client.fhir.resolve_batch([
    {"system": "http://snomed.info/sct", "code": "44054006"},
    {"system": "http://loinc.org", "code": "2339-0"},
    {"system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "197696"},
])

print(result["summary"])  # {"total": 3, "resolved": 3, "failed": 0}

for item in result["results"]:
    if "resolution" in item:
        res = item["resolution"]
        print(f"{res['source_concept']['concept_code']} -> {res['standard_concept']['concept_name']} -> {res['target_table']}")
    else:
        print(f"Failed: {item['error']['code']} - {item['error']['message']}")
```

Apply shared options to the entire batch:

```python theme={null}
result = client.fhir.resolve_batch(
    [{"system": "http://snomed.info/sct", "code": "44054006"}],
    resource_type="Condition",
    include_quality=True,
)
```

## CodeableConcept Resolution

Resolve a FHIR `CodeableConcept` with multiple codings. The resolver picks the best match per OHDSI vocabulary preference (SNOMED > RxNorm > LOINC > CVX > ICD-10):

```python theme={null}
result = client.fhir.resolve_codeable_concept(
    coding=[
        {"system": "http://snomed.info/sct", "code": "44054006"},
        {"system": "http://hl7.org/fhir/sid/icd-10-cm", "code": "E11.9"},
    ],
    resource_type="Condition",
)

best = result["best_match"]["resolution"]
print(best["source_concept"]["vocabulary_id"])  # "SNOMED" (preferred)
print(best["target_table"])                     # "condition_occurrence"

# Other resolved codings ranked by preference
for alt in result["alternatives"]:
    print(f"  Alt: {alt['resolution']['source_concept']['vocabulary_id']}")

# Codings that failed to resolve
for fail in result["unresolved"]:
    print(f"  Failed: {fail['error']['code']}")
```

Falls back to the `text` field via semantic search when no coding resolves:

```python theme={null}
result = client.fhir.resolve_codeable_concept(
    coding=[{"system": "http://loinc.org", "code": "99999-9"}],
    text="Blood Sugar",
    resource_type="Observation",
)
# best_match resolved via semantic search; failed coding in unresolved
```

## Async Usage

All three methods are available on the async client:

```python theme={null}
async with omophub.AsyncOMOPHub(api_key="oh_xxx") as client:
    result = await client.fhir.resolve(
        system="http://snomed.info/sct",
        code="44054006",
    )
    batch = await client.fhir.resolve_batch([
        {"system": "http://loinc.org", "code": "2339-0"},
    ])
    cc = await client.fhir.resolve_codeable_concept(
        coding=[{"system": "http://snomed.info/sct", "code": "44054006"}],
    )
```

## Type Interoperability

All resolver methods accept any Coding-like input via duck typing. You can pass a plain dict, an `omophub.types.fhir.Coding` TypedDict, or any object exposing `.system` / `.code` attributes - including `fhir.resources.Coding` and `fhirpy` coding instances. `fhir.resources` is **never** a required dependency.

```python theme={null}
# 1. Plain dict (no extra install)
client.fhir.resolve(
    coding={"system": "http://snomed.info/sct", "code": "44054006"},
)

# 2. omophub's lightweight Coding TypedDict
from omophub.types.fhir import Coding, CodeableConcept

coding: Coding = {"system": "http://snomed.info/sct", "code": "44054006"}
client.fhir.resolve(coding=coding)

cc: CodeableConcept = {
    "coding": [
        {"system": "http://snomed.info/sct", "code": "44054006"},
        {"system": "http://hl7.org/fhir/sid/icd-10-cm", "code": "E11.9"},
    ],
    "text": "Type 2 diabetes mellitus",
}
client.fhir.resolve_codeable_concept(cc)

# 3. fhir.resources objects via duck typing (optional install)
# pip install omophub[fhir-resources]
from fhir.resources.R4B.coding import Coding as FhirCoding

fhir_coding = FhirCoding(system="http://snomed.info/sct", code="44054006")
client.fhir.resolve(coding=fhir_coding)
```

Mixed-shape inputs are fine inside a single batch call - dicts, TypedDicts, and `fhir.resources` objects can coexist:

```python theme={null}
from fhir.resources.R4B.coding import Coding as FhirCoding

result = client.fhir.resolve_batch([
    {"system": "http://snomed.info/sct", "code": "44054006"},
    FhirCoding(system="http://loinc.org", code="2339-0"),
])
```

Explicit `system` / `code` kwargs always win if you pass both `coding=` and explicit kwargs - handy for overriding a single field without rebuilding the object.

## Connection Helpers

For users who want to point an external FHIR client library at OMOPHub's FHIR Terminology Service directly, the SDK exposes two helpers: a URL builder and a pre-wired `fhirpy` client.

```python theme={null}
from omophub import OMOPHub, get_fhir_server_url, get_fhirpy_client

client = OMOPHub(api_key="oh_xxx")

# Property on the client - returns the R4 base URL
print(client.fhir_server_url)
# "https://fhir.omophub.com/fhir/r4"

# Helper for other FHIR versions
print(get_fhir_server_url("r5"))
# "https://fhir.omophub.com/fhir/r5"
```

### fhirpy (optional extra)

If you want to call FHIR operations directly - outside the SDK's Concept Resolver envelope - install `fhirpy` as an optional extra:

```bash theme={null}
pip install omophub[fhirpy]
```

Then use the pre-configured client:

```python theme={null}
from omophub import get_fhirpy_client

fhir = get_fhirpy_client("oh_xxx")

# Example: fetch the CodeSystem discovery Bundle for SNOMED
bundle = fhir.resources("CodeSystem").search(
    url="http://snomed.info/sct",
).fetch()

# Example: call $lookup directly via fhirpy
lookup = fhir.execute(
    "CodeSystem/$lookup",
    method="GET",
    params={"system": "http://snomed.info/sct", "code": "44054006"},
)
```

`get_async_fhirpy_client()` is the async counterpart.

<Note>
  Use the Concept Resolver (`client.fhir.resolve`) when you want OMOP-enriched answers - standard concept ID, CDM target table, mapping quality. Use `fhirpy` against `client.fhir_server_url` when you need raw FHIR `Parameters` / `Bundle` responses for FHIR-native tooling.
</Note>

## Error Handling

The resolver raises standard SDK errors for API failures:

```python theme={null}
from omophub import APIError

try:
    result = client.fhir.resolve(
        system="http://www.ama-assn.org/go/cpt",
        code="99213",
    )
except APIError as e:
    print(e.status_code)  # 403
    print(e.message)       # "vocabulary_restricted"
```

| Error Code          | HTTP | Cause                                                                       |
| ------------------- | ---- | --------------------------------------------------------------------------- |
| `unknown_system`    | 400  | FHIR code system URI not recognized (includes a typo suggestion when close) |
| `missing_input`     | 400  | Neither `(system + code)` / `(vocabulary_id + code)` / `display` provided   |
| `concept_not_found` | 404  | No concept found via lookup or semantic search                              |

<Note>
  See the [FHIR Resolver API Reference](/api-reference/fhir/resolve) for full response schemas and field descriptions.
</Note>
