Skip to navigation

Normalizing terms and codes

Matching preferences, transformations, and filters — the controls that shape your results.

POST /precision/normalize/v1 is the general-purpose engine. It works across all clinical domains, is code-system agnostic, and honors your custom lexical maps.

Term-based vs code-based matching

You supplyBehavior
input_termFuzzy, scored matching. Returns every lexical at or above threshold, ranked.
input_code + input_code_systemDeterministic lookup. Returns at most one lexical with score: 1.
Bothpreferences.match_field_pref decides which wins.

The response’s response.match_field tells you which path was actually taken.

Choosing between them

{
"client_request_id": "batch-001",
"preferences": { "match_field_pref": "input_code_first" },
"requests": [
{
"record_id": "1",
"domain": "Problem",
"input_term": "chest pain",
"input_code": "R07.9",
"input_code_system": "ICD-10-CM"
}
]
}
match_field_prefMeaning
input_termOnly ever match on the term
input_codeOnly ever match on the code
input_term_firstTry the term; fall back to the code
input_code_firstTry the code; fall back to the term

Preferences

threshold
numberDefaults to varies by domain

Minimum score a lexical must reach to be returned, up to 3 decimal places. Irrelevant for code-based matching, where a match is always 1.

size
integer

Maximum lexicals returned per record. When more match than the limit, the highest-scoring win; ties break toward the more concise lexical.

distinct_field
enum

lexical_code or default_lexical_code. Which field to de-duplicate results on.

discrepancy_check
boolean

When true, flags records where the supplied term and code disagree. The mismatch surfaces in each item’s discrepancy object.

use_custom_maps
boolean

Apply your organization’s custom lexical mappings before falling back to IMO’s standard content.

use_domain_relevance_filter
boolean

Drop matches that don’t belong to the requested domain.

use_semantic_match
boolean

Enable semantic (meaning-based) matching in addition to lexical similarity.

Transformations

Transformations rewrite the input term before matching — useful for stripping site-specific prefixes or expanding local abbreviations.

{
"preferences": {
"transformations": [
{ "type": "string_replace", "from": "hx of ", "to": "history of ",
"location": "beginning" },
{ "type": "multiple_string_replace", "from": ["r/o", "R/O"],
"to": "rule out", "location": "*" }
]
}
}
FieldValues
typestring_replace, multiple_string_replace
locationbeginning, end, * (anywhere)

The rewritten term comes back as transformed_term on both the record and its response, so you can see exactly what was matched.

Filters

Filters constrain results to a subset of IMO content — currently scoped to USCDI profile attributes.

{
"preferences": {
"filters": [
{ "field": "uscdi.profiles.data_class", "operator": "eq",
"value": "Health Status Assessments" }
]
}
}
FieldPurpose
uscdi.profiles.valueset_oidRestrict to a specific USCDI value set
uscdi.profiles.hrsn_domainRestrict to a health-related social needs domain
uscdi.profiles.data_elementRestrict to a USCDI data element
uscdi.profiles.data_classRestrict to a USCDI data class

Only the eq operator is supported today.

Batching

One request carries up to 300 records. Batch aggressively — it amortizes round-trip latency and counts as a single call against your rate limit.

const rows = await loadClinicalRows(); // your data
// The API caps a batch at 300 records.
for (let i = 0; i < rows.length; i += 300) {
const chunk = rows.slice(i, i + 300);
const result = await client.normalize.normalize({
clientRequestId: `batch-${i / 300}`,
preferences: { threshold: 0.5, size: 1 },
requests: chunk.map((row) => ({
recordId: row.id,
domain: "Problem",
inputTerm: row.text,
})),
});
await persist(result.requests ?? []);
}

Exceeding 300 records returns 413 Payload Too Large. Chunk client-side.

Lab results and LOINC parts

For the Lab domain, supplying LOINC axis hints in context sharply improves matching, and the response returns resolved loinc_parts:

{
"record_id": "lab-1",
"domain": "Lab",
"input_term": "hemoglobin",
"context": {
"unit_of_measure": "g/dL",
"sample_type": "Blood",
"loinc_property": "MCnc"
}
}

The matching response.loinc_parts breaks out component, property, sample_type, method, scale, and time.