curl -X GET "https://api.omophub.com/v1/concepts/73211009/descendants?include_distance=true&max_levels=3" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
concept_id = 73211009 # Diabetes mellitus
url = f"https://api.omophub.com/v1/concepts/{concept_id}/descendants"
params = {
"include_distance": True,
"max_levels": 3,
"page_size": 50
}
headers = {
"Authorization": "Bearer YOUR_API_KEY"
}
response = requests.get(url, params=params, headers=headers)
descendant_data = response.json()
print(f"Concept: {descendant_data['concept_name']}")
print(f"Total descendants: {descendant_data['hierarchy_summary']['total_descendants']}")
import { OMOPHub } from '@omophub/omophub-node';
const client = new OMOPHub();
const { data: descendantData } = await client.hierarchy.descendants(73211009, {
includeDistance: true,
maxLevels: 3,
});
console.log(`Found ${descendantData?.hierarchy_summary.total_descendants} descendants`);
console.log(`Max depth: ${descendantData?.hierarchy_summary.max_hierarchy_depth}`);
curl -X GET "https://api.omophub.com/v1/concepts/73211009/descendants?domain_ids=Condition&max_levels=2&page_size=25" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
from collections import defaultdict
concept_id = 73211009
response = requests.get(
f"https://api.omophub.com/v1/concepts/{concept_id}/descendants",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"include_distance": True, "max_levels": 3}
)
data = response.json()
by_level = defaultdict(list)
for desc in data['descendants']:
level = desc.get('hierarchy_level', 0)
by_level[level].append(desc['concept_name'])
for level in sorted(by_level.keys()):
print(f"Level {level}: {len(by_level[level])} concepts")
{
"success": true,
"data": {
"concept_id": 73211009,
"concept_name": "Diabetes mellitus",
"vocabulary_id": "SNOMED",
"descendants": [
{
"concept_id": 44054006,
"concept_name": "Type 2 diabetes mellitus",
"concept_code": "44054006",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 1,
"min_levels_of_separation": 1,
"max_levels_of_separation": 1,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 1,
"valid_start_date": "1970-01-01",
"valid_end_date": "2099-12-31",
"invalid_reason": null
},
{
"concept_id": 46635009,
"concept_name": "Type 1 diabetes mellitus",
"concept_code": "46635009",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 1,
"min_levels_of_separation": 1,
"max_levels_of_separation": 1,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 1,
"valid_start_date": "1970-01-01",
"valid_end_date": "2099-12-31",
"invalid_reason": null
},
{
"concept_id": 237599002,
"concept_name": "Insulin dependent diabetes mellitus",
"concept_code": "237599002",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 2,
"min_levels_of_separation": 2,
"max_levels_of_separation": 2,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 2,
"valid_start_date": "2002-01-31",
"valid_end_date": "2099-12-31",
"invalid_reason": null
}
],
"hierarchy_summary": {
"total_descendants": 847,
"truncated": false,
"result_limit": 5000,
"max_hierarchy_depth": 6,
"unique_vocabularies": ["SNOMED"],
"relationship_types_used": ["Subsumes"]
}
},
"meta": {
"pagination": {
"page": 1,
"page_size": 100,
"total_items": 847,
"total_pages": 9,
"has_next": true,
"has_previous": false
},
"request_id": "req_descendants_123",
"timestamp": "2024-12-22T10:00:00Z",
"vocab_release": "2025.2"
}
}
Get Concept Descendants
Retrieve all descendant OMOP concepts for a given concept - hierarchical children and specialized terms for phenotype and cohort definitions.
curl -X GET "https://api.omophub.com/v1/concepts/73211009/descendants?include_distance=true&max_levels=3" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
concept_id = 73211009 # Diabetes mellitus
url = f"https://api.omophub.com/v1/concepts/{concept_id}/descendants"
params = {
"include_distance": True,
"max_levels": 3,
"page_size": 50
}
headers = {
"Authorization": "Bearer YOUR_API_KEY"
}
response = requests.get(url, params=params, headers=headers)
descendant_data = response.json()
print(f"Concept: {descendant_data['concept_name']}")
print(f"Total descendants: {descendant_data['hierarchy_summary']['total_descendants']}")
import { OMOPHub } from '@omophub/omophub-node';
const client = new OMOPHub();
const { data: descendantData } = await client.hierarchy.descendants(73211009, {
includeDistance: true,
maxLevels: 3,
});
console.log(`Found ${descendantData?.hierarchy_summary.total_descendants} descendants`);
console.log(`Max depth: ${descendantData?.hierarchy_summary.max_hierarchy_depth}`);
curl -X GET "https://api.omophub.com/v1/concepts/73211009/descendants?domain_ids=Condition&max_levels=2&page_size=25" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
from collections import defaultdict
concept_id = 73211009
response = requests.get(
f"https://api.omophub.com/v1/concepts/{concept_id}/descendants",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"include_distance": True, "max_levels": 3}
)
data = response.json()
by_level = defaultdict(list)
for desc in data['descendants']:
level = desc.get('hierarchy_level', 0)
by_level[level].append(desc['concept_name'])
for level in sorted(by_level.keys()):
print(f"Level {level}: {len(by_level[level])} concepts")
{
"success": true,
"data": {
"concept_id": 73211009,
"concept_name": "Diabetes mellitus",
"vocabulary_id": "SNOMED",
"descendants": [
{
"concept_id": 44054006,
"concept_name": "Type 2 diabetes mellitus",
"concept_code": "44054006",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 1,
"min_levels_of_separation": 1,
"max_levels_of_separation": 1,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 1,
"valid_start_date": "1970-01-01",
"valid_end_date": "2099-12-31",
"invalid_reason": null
},
{
"concept_id": 46635009,
"concept_name": "Type 1 diabetes mellitus",
"concept_code": "46635009",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 1,
"min_levels_of_separation": 1,
"max_levels_of_separation": 1,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 1,
"valid_start_date": "1970-01-01",
"valid_end_date": "2099-12-31",
"invalid_reason": null
},
{
"concept_id": 237599002,
"concept_name": "Insulin dependent diabetes mellitus",
"concept_code": "237599002",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 2,
"min_levels_of_separation": 2,
"max_levels_of_separation": 2,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 2,
"valid_start_date": "2002-01-31",
"valid_end_date": "2099-12-31",
"invalid_reason": null
}
],
"hierarchy_summary": {
"total_descendants": 847,
"truncated": false,
"result_limit": 5000,
"max_hierarchy_depth": 6,
"unique_vocabularies": ["SNOMED"],
"relationship_types_used": ["Subsumes"]
}
},
"meta": {
"pagination": {
"page": 1,
"page_size": 100,
"total_items": 847,
"total_pages": 9,
"has_next": true,
"has_previous": false
},
"request_id": "req_descendants_123",
"timestamp": "2024-12-22T10:00:00Z",
"vocab_release": "2025.2"
}
}
This endpoint returns all descendant concepts (children, grandchildren, etc.) for a specific concept, allowing exploration of more specific terms and sub-classifications within the medical vocabulary hierarchy.
Path Parameters
integer
required
The unique identifier of the concept to retrieve descendants for
Example:
Example:
73211009 (Diabetes mellitus)Query Parameters
string
Filter descendants to specific vocabularies (comma-separated)
Example:
Example:
SNOMED,ICD10CMstring
Filter descendants to specific domains (comma-separated)
Example:
Example:
Condition,Druginteger
default:"10"
Maximum number of hierarchy levels to traverse downward
Range:
Range:
1-20This endpoint always traverses the
Is a / Subsumes hierarchy. It reads
OMOP’s precomputed concept_ancestor closure, which stores only transitive
subsumption - it has no relationship column to filter on. Every descendant is
therefore returned with relationship_id: "Subsumes".A relationship_types parameter is accepted for backwards compatibility but has
no effect here: passing Has part, or even a nonexistent relationship, returns
the same descendants. To traverse other relationship types, use
GET /v1/concepts/{concept_id}/relationships
or POST /v1/concepts/relationships/traverse,
which query concept_relationship directly.boolean
default:"false"
Include
hierarchy_level field for each descendant (distance from source concept)boolean
default:"false"
Include
path_length field for each descendantboolean
default:"false"
Include deprecated/invalid concepts in descendants (by default they are excluded)
integer
default:"5000"
Maximum size of the descendant set to retrieve before pagination is applied.
Range:
Defaults to the maximum, so paging through the response returns every descendant that matches this request - that is, those within
Range:
1-5000Defaults to the maximum, so paging through the response returns every descendant that matches this request - that is, those within
max_levels and any
domain_ids / vocabulary_ids filters you supplied. (relationship_types is not
applied - see above.) It is not necessarily the concept’s entire descendant
closure: max_levels defaults to 10, so deeper descendants are excluded, and
truncated does not flag that (it reports the row cap only). For a full
closure, pass max_levels=20 as well.Lower max_results only if you deliberately want a partial set - note that
total_items then reflects the truncated set, not the true descendant count. To
read the true, unfiltered count without fetching the set, use
GET /v1/concepts/{concept_id}/level.integer
default:"1"
Page number for pagination (1-based)
integer
default:"100"
Number of descendant concepts to return per page. Values above
200 are
clamped to 200.string
Specific vocabulary release version to query
Example:
Example:
2025.1Response
integer
The concept ID for which descendants were retrieved
string
Standard name of the source concept
string
Vocabulary containing the source concept
array
Array of descendant concepts in hierarchical order
Show Descendant Concept Object
Show Descendant Concept Object
integer
Unique identifier for the descendant concept
string
Standard name of the descendant concept
string
Original code from the vocabulary
string
Vocabulary containing this descendant concept
string
Human-readable vocabulary name
string
Domain classification of the descendant
string
Concept class identifier
string
Standard concept designation (‘S’, ‘C’, or null)
integer
Distance from source concept (always present)
integer
Minimum levels of separation from source concept
integer
Maximum levels of separation from source concept
string
Relationship type ID (e.g., “Subsumes”)
string
Relationship type name (e.g., “Subsumes”)
integer
Distance from source concept (only when include_distance=true, same as level)
integer
Path length from source concept (only when include_paths=true, same as level)
string
Date when concept became valid (ISO format)
string
Date when concept became invalid (ISO format)
string
Reason for concept invalidation if applicable
object
Summary statistics about the descendant hierarchy
Show Hierarchy Summary Object
Show Hierarchy Summary Object
integer
Number of descendant concepts retrieved. When
truncated is true this is
the size of the retrieved subset, not the true descendant count.boolean
true when the concept has more matching descendants than result_limit
and the response holds only the first result_limit of them. The pagination
metadata then describes the retrieved subset, so paging to the last page
does not give you everything.Always check this before building a concept set from the response - a
truncated set is otherwise indistinguishable from a complete one, and the
resulting cohort is silently under-counted. To recover: narrow the query
with domain_ids / vocabulary_ids, or split the concept into several
narrower roots.truncated reports the row cap only. It does not tell you whether
descendants were dropped by max_levels, which defaults to 10 - a
response can be depth-limited and still report truncated: false. Pass
max_levels=20 if you need the full closure.GET /v1/concepts/{concept_id}/level
reports the true (unfiltered, undepth-limited) descendant count, which is
the reliable way to check a response for completeness.integer
The row cap applied to this request - the effective
max_results.integer
Maximum depth of the descendant tree
array
List of vocabulary IDs represented in descendants
array
List of relationship type IDs found in hierarchy
object
curl -X GET "https://api.omophub.com/v1/concepts/73211009/descendants?include_distance=true&max_levels=3" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
concept_id = 73211009 # Diabetes mellitus
url = f"https://api.omophub.com/v1/concepts/{concept_id}/descendants"
params = {
"include_distance": True,
"max_levels": 3,
"page_size": 50
}
headers = {
"Authorization": "Bearer YOUR_API_KEY"
}
response = requests.get(url, params=params, headers=headers)
descendant_data = response.json()
print(f"Concept: {descendant_data['concept_name']}")
print(f"Total descendants: {descendant_data['hierarchy_summary']['total_descendants']}")
import { OMOPHub } from '@omophub/omophub-node';
const client = new OMOPHub();
const { data: descendantData } = await client.hierarchy.descendants(73211009, {
includeDistance: true,
maxLevels: 3,
});
console.log(`Found ${descendantData?.hierarchy_summary.total_descendants} descendants`);
console.log(`Max depth: ${descendantData?.hierarchy_summary.max_hierarchy_depth}`);
curl -X GET "https://api.omophub.com/v1/concepts/73211009/descendants?domain_ids=Condition&max_levels=2&page_size=25" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
from collections import defaultdict
concept_id = 73211009
response = requests.get(
f"https://api.omophub.com/v1/concepts/{concept_id}/descendants",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"include_distance": True, "max_levels": 3}
)
data = response.json()
by_level = defaultdict(list)
for desc in data['descendants']:
level = desc.get('hierarchy_level', 0)
by_level[level].append(desc['concept_name'])
for level in sorted(by_level.keys()):
print(f"Level {level}: {len(by_level[level])} concepts")
{
"success": true,
"data": {
"concept_id": 73211009,
"concept_name": "Diabetes mellitus",
"vocabulary_id": "SNOMED",
"descendants": [
{
"concept_id": 44054006,
"concept_name": "Type 2 diabetes mellitus",
"concept_code": "44054006",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 1,
"min_levels_of_separation": 1,
"max_levels_of_separation": 1,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 1,
"valid_start_date": "1970-01-01",
"valid_end_date": "2099-12-31",
"invalid_reason": null
},
{
"concept_id": 46635009,
"concept_name": "Type 1 diabetes mellitus",
"concept_code": "46635009",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 1,
"min_levels_of_separation": 1,
"max_levels_of_separation": 1,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 1,
"valid_start_date": "1970-01-01",
"valid_end_date": "2099-12-31",
"invalid_reason": null
},
{
"concept_id": 237599002,
"concept_name": "Insulin dependent diabetes mellitus",
"concept_code": "237599002",
"vocabulary_id": "SNOMED",
"vocabulary_name": "SNOMED Clinical Terms",
"domain_id": "Condition",
"concept_class_id": "Clinical Finding",
"standard_concept": "S",
"level": 2,
"min_levels_of_separation": 2,
"max_levels_of_separation": 2,
"relationship_id": "Subsumes",
"relationship_name": "Subsumes",
"hierarchy_level": 2,
"valid_start_date": "2002-01-31",
"valid_end_date": "2099-12-31",
"invalid_reason": null
}
],
"hierarchy_summary": {
"total_descendants": 847,
"truncated": false,
"result_limit": 5000,
"max_hierarchy_depth": 6,
"unique_vocabularies": ["SNOMED"],
"relationship_types_used": ["Subsumes"]
}
},
"meta": {
"pagination": {
"page": 1,
"page_size": 100,
"total_items": 847,
"total_pages": 9,
"has_next": true,
"has_previous": false
},
"request_id": "req_descendants_123",
"timestamp": "2024-12-22T10:00:00Z",
"vocab_release": "2025.2"
}
}
Usage Examples
Note: Examples assume a preconfiguredclient from new OMOPHub(). For direct usage:
TypeScript
import { OMOPHub } from '@omophub/omophub-node';
const client = new OMOPHub();
const { data } = await client.hierarchy.descendants(73211009);
Basic Descendant Retrieval
Get all descendants for a specific concept:TypeScript
const { data: descendants } = await client.hierarchy.descendants(73211009);
Limited Hierarchy Depth
Retrieve descendants up to a specific number of levels:TypeScript
const { data: nearDescendants } = await client.hierarchy.descendants(73211009, { maxLevels: 2 });
Domain-Specific Descendants
Filter descendants to specific medical domains:TypeScript
const { data: conditionDescendants } = await client.hierarchy.descendants(73211009, {
domainIds: ['Condition'],
});
Detailed Descendant Information
Get descendants with hierarchy levels and path information:TypeScript
const { data: detailedData } = await client.hierarchy.descendants(73211009, {
includeDistance: true,
includePaths: true,
});
Related Endpoints
- Get Concept Ancestors - Retrieve parent concepts
- Get Concept Hierarchy - Complete hierarchy view
- Get Concept Relationships - All concept relationships
- Search Concepts - Search within specific hierarchies
Notes
- Descendant traversal follows “Is a” relationships by default, but can include other relationship types
- Large hierarchies may contain thousands of descendants - use pagination and filtering appropriately
- Standard concepts are prioritized unless explicitly disabled
- Some medical concepts may have very deep hierarchies (6+ levels)
- Cross-vocabulary concepts may have descendants from multiple vocabularies
- Deprecated concepts are excluded from descendants unless specifically requested with
include_invalid=true
Was this page helpful?