> ## 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.

# Quickstart - search, map, and resolve codes in 5 min

> Get up and running with the OMOPHub API in five minutes - search OMOP concepts, map across vocabularies, and resolve FHIR codes to standard CDM types.

Get up and running with the OMOPHub API in 5 minutes.

## Prerequisites

You'll need:

* An OMOPHub account ([sign up here](https://dashboard.omophub.com/register))
* An API key ([generate one here](https://dashboard.omophub.com/api-keys))
* Python 3.10+, R 4.1+, or cURL

## Step 1: Install the SDK

<CodeGroup>
  ```bash Python theme={null}
  pip install omophub
  ```

  ```r R theme={null}
  install.packages("omophub")
  ```

  ```bash cURL theme={null}
  # No installation needed - just your API key
  ```
</CodeGroup>

## Step 2: Set Up Authentication

<CodeGroup>
  ```python Python theme={null}
  import omophub

  # Option 1: environment variable (recommended)
  # export OMOPHUB_API_KEY="oh_xxxxxxxxx"
  client = omophub.OMOPHub()

  # Option 2: pass directly
  client = omophub.OMOPHub(api_key="oh_xxxxxxxxx")
  ```

  ```r R theme={null}
  library(omophub)

  # Option 1: environment variable (recommended)
  # Sys.setenv(OMOPHUB_API_KEY = "oh_xxxxxxxxx")
  client <- OMOPHubClient$new()

  # Option 2: pass directly
  client <- OMOPHubClient$new(api_key = "oh_xxxxxxxxx")
  ```

  ```bash cURL theme={null}
  # Include in every request header
  curl -H "Authorization: Bearer oh_xxxxxxxxx" \
    "https://api.omophub.com/v1/vocabularies"
  ```
</CodeGroup>

<Warning>
  Never hardcode your API key in source code. Use environment variables or a secrets manager in production.
</Warning>

## Step 3: Search for Concepts

Search across 11M+ concepts by keyword, then by meaning:

<CodeGroup>
  ```python Python theme={null}
  # Keyword search
  results = client.search.basic("hypertension", page_size=5)
  for concept in results["concepts"]:
      print(f"{concept['concept_id']}: {concept['concept_name']} ({concept['vocabulary_id']})")

  # Semantic search - find concepts by clinical meaning, not just keyword match
  results = client.search.semantic("high blood pressure that comes and goes", page_size=5)
  for concept in results["concepts"]:
      print(f"{concept['concept_id']}: {concept['concept_name']}")
  ```

  ```r R theme={null}
  # Keyword search
  results <- client$search$basic("hypertension", page_size = 5)
  for (concept in results$concepts) {
    cat(sprintf("%s: %s (%s)\n",
      concept$concept_id, concept$concept_name, concept$vocabulary_id))
  }

  # Semantic search - find concepts by clinical meaning
  results <- client$search$semantic(
    "high blood pressure that comes and goes",
    page_size = 5
  )
  ```

  ```bash cURL theme={null}
  # Keyword search
  curl "https://api.omophub.com/v1/search/concepts?query=hypertension&page_size=5" \
    -H "Authorization: Bearer oh_xxxxxxxxx"

  # Semantic search
  curl "https://api.omophub.com/v1/concepts/semantic-search?query=high+blood+pressure+that+comes+and+goes&page_size=5" \
    -H "Authorization: Bearer oh_xxxxxxxxx"
  ```
</CodeGroup>

<Tip>
  Semantic search uses neural embeddings to match by clinical meaning. Try it when keyword search doesn't find what you need - it handles synonyms, abbreviations, and natural-language descriptions.
</Tip>

## Step 4: Get Concept Details

Look up a specific concept by its OMOP `concept_id`:

<CodeGroup>
  ```python Python theme={null}
  concept = client.concepts.get(201826)
  print(f"Name:       {concept['concept_name']}")        # Type 2 diabetes mellitus
  print(f"Code:       {concept['concept_code']}")         # 44054006
  print(f"Vocabulary: {concept['vocabulary_id']}")        # SNOMED
  print(f"Domain:     {concept['domain_id']}")            # Condition
  print(f"Standard:   {concept['standard_concept']}")     # S
  ```

  ```r R theme={null}
  concept <- client$concepts$get(201826)
  cat(sprintf("Name: %s\n",       concept$concept_name))
  cat(sprintf("Code: %s\n",       concept$concept_code))
  cat(sprintf("Vocabulary: %s\n", concept$vocabulary_id))
  cat(sprintf("Domain: %s\n",     concept$domain_id))
  ```

  ```bash cURL theme={null}
  curl "https://api.omophub.com/v1/concepts/201826" \
    -H "Authorization: Bearer oh_xxxxxxxxx"
  ```
</CodeGroup>

## Step 5: Navigate Hierarchies

Walk the ancestor / descendant tree to expand a concept set:

<CodeGroup>
  ```python Python theme={null}
  # Ancestors (parents)
  result = client.hierarchy.ancestors(201826, max_levels=2)
  for ancestor in result["ancestors"]:
      level = ancestor.get("hierarchy_level", 0)
      print(f"{'  ' * level}{ancestor['concept_name']}")

  # Descendants (children)
  result = client.hierarchy.descendants(201826, max_levels=1)
  print(f"\n{len(result['descendants'])} child concepts")
  ```

  ```r R theme={null}
  # Ancestors
  result <- client$hierarchy$ancestors(201826, max_levels = 2)
  for (ancestor in result$ancestors) {
    level <- if (is.null(ancestor$hierarchy_level)) 0 else ancestor$hierarchy_level
    cat(strrep("  ", level), ancestor$concept_name, "\n", sep = "")
  }

  # Descendants
  result <- client$hierarchy$descendants(201826, max_levels = 1)
  cat(sprintf("%d child concepts\n", length(result$descendants)))
  ```

  ```bash cURL theme={null}
  # Ancestors
  curl "https://api.omophub.com/v1/concepts/201826/ancestors?max_levels=2" \
    -H "Authorization: Bearer oh_xxxxxxxxx"

  # Descendants
  curl "https://api.omophub.com/v1/concepts/201826/descendants?max_levels=1" \
    -H "Authorization: Bearer oh_xxxxxxxxx"
  ```
</CodeGroup>

## Step 6: Map Between Vocabularies

Translate codes across SNOMED, ICD-10, LOINC, RxNorm, and every other OMOP vocabulary:

<CodeGroup>
  ```python Python theme={null}
  # Map SNOMED "Type 2 diabetes" to ICD-10-CM
  result = client.mappings.get(201826, target_vocabulary="ICD10CM")
  for m in result["data"]["mappings"]:
      print(f"{m['relationship_id']}: {m['target_concept_name']} "
            f"({m['target_vocabulary_id']}: {m['target_concept_code']})")
  ```

  ```r R theme={null}
  result <- client$mappings$get(201826, target_vocabulary = "ICD10CM")
  for (m in result$data$mappings) {
    cat(sprintf("%s: %s (%s: %s)\n",
      m$relationship_id,
      m$target_concept_name,
      m$target_vocabulary_id,
      m$target_concept_code
    ))
  }
  ```

  ```bash cURL theme={null}
  curl "https://api.omophub.com/v1/concepts/201826/mappings?target_vocabularies=ICD10CM" \
    -H "Authorization: Bearer oh_xxxxxxxxx"
  ```
</CodeGroup>

<Tip>
  For ETL workloads, the batch endpoint `client.mappings.map(target_vocabulary="...", source_concepts=[...])` maps up to 100 concepts per request and counts as a single API call against your quota.
</Tip>

## Step 7: Resolve a FHIR Code to OMOP

This is the single call no other terminology server offers - send a FHIR `Coding` (system URI + code), get back the OMOP standard concept, domain, mapping type, and the exact CDM target table for ETL placement:

<CodeGroup>
  ```python Python theme={null}
  result = client.fhir.resolve(
      system="http://snomed.info/sct",
      code="44054006",
      resource_type="Condition",
  )
  res = result["resolution"]
  print(f"Standard concept: {res['standard_concept']['concept_id']} - {res['standard_concept']['concept_name']}")
  print(f"Domain:           {res['standard_concept']['domain_id']}")
  print(f"Target table:     {res['target_table']}")         # condition_occurrence
  print(f"Mapping type:     {res['mapping_type']}")         # direct
  ```

  ```r R theme={null}
  result <- client$fhir$resolve(
    system = "http://snomed.info/sct",
    code = "44054006",
    resource_type = "Condition"
  )
  res <- result$resolution
  cat(sprintf("Standard concept: %d - %s\n",
    res$standard_concept$concept_id,
    res$standard_concept$concept_name))
  cat(sprintf("Target table: %s\n", res$target_table))
  cat(sprintf("Mapping type: %s\n", res$mapping_type))
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.omophub.com/v1/fhir/resolve" \
    -H "Authorization: Bearer oh_xxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "system": "http://snomed.info/sct",
      "code": "44054006",
      "resource_type": "Condition"
    }'
  ```
</CodeGroup>

<Info>
  The Resolver handles URI → OMOP vocabulary lookup, `Maps to` traversal for non-standard codes, and semantic fallback for display-text-only inputs in a single call. For the full response shape, batch variants, and the `CodeableConcept` endpoint, see the [FHIR Integration guide](/guides/integration/fhir-integration).
</Info>

## Next Steps

<CardGroup cols={2}>
  <Card title="FHIR Integration" icon="arrows-rotate" href="/guides/integration/fhir-integration">
    The complete FHIR story - Resolver for ETL, Terminology Service for clients, and when to use which.
  </Card>

  <Card title="FHIR Terminology Service" icon="fire" href="/api-reference/fhir-terminology/overview">
    `$lookup`, `$translate`, `$validate-code`, `$expand`, `$subsumes` reference.
  </Card>

  <Card title="AI & MCP Server" icon="robot" href="/ai/onboarding">
    Connect Claude, Cursor, or VS Code to medical vocabularies via the MCP Server.
  </Card>

  <Card title="Python SDK" icon="python" href="/sdks/python/overview">
    Full SDK reference: search, concepts, hierarchy, mappings, FHIR resolver.
  </Card>

  <Card title="R SDK" icon="r-project" href="/sdks/r/overview">
    R6 client for vocabulary access in R workflows.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Complete endpoint documentation with request / response schemas.
  </Card>

  <Card title="Workflows" icon="lightbulb" href="/guides/use-cases/clinical-coding">
    Real-world workflows: clinical coding, phenotype development, lab normalization, and more.
  </Card>
</CardGroup>

## Common Issues

<AccordionGroup>
  <Accordion title="401 Unauthorized">
    * Check that your API key is correct and starts with `oh_`
    * Ensure the `Authorization: Bearer <key>` header format is exact
    * Verify the key at [dashboard.omophub.com/api-keys](https://dashboard.omophub.com/api-keys)
  </Accordion>

  <Accordion title="429 Rate Limited">
    * Free tier: 2 requests per second, monthly call quota per plan
    * Use batch endpoints (concepts, mappings, semantic search) to reduce call count - each batch counts as one API call
    * Respect the `Retry-After` response header
    * See [Rate Limits](/api-reference/rate-limit) for plan-specific limits
  </Accordion>

  <Accordion title="No Results Found">
    * Try broader search terms or remove filters
    * Use semantic search for natural-language queries (Step 3)
    * Check `vocabulary_id` spelling - it's `SNOMED`, not `SNOMED-CT`; `ICD10CM`, not `ICD-10-CM`
    * Confirm the target vocabulary is currently supported via `client.vocabularies.list()`
  </Accordion>
</AccordionGroup>
