Guide · Node.js · Healthcare · REST API

ICD-10 Validation in Node.js — Medical Diagnosis Codes

Every diagnosis on a medical claim, discharge summary, or death certificate in most of the world is encoded as an ICD-10 code. Here's how the classification works, the difference between WHO ICD-10 and the US ICD-10-CM superset, and how to validate codes in a Node.js application with the IsValid API.

1. What is ICD-10?

ICD-10 is the 10th revision of the International Classification of Diseases, a standardised taxonomy of diseases, injuries, and causes of death maintained by the World Health Organization. First published in 1992, ICD-10 is used in more than 100 countries for mortality reporting, morbidity surveillance, clinical documentation, and healthcare reimbursement.

Each ICD-10 code represents a single diagnosis, condition, or cause of death. Codes are organised into 22 chapters covering broad body systems and disease categories — infectious diseases, neoplasms, circulatory system, injuries, external causes, and so on. Each chapter is subdivided into blocks, categories, and highly specific sub-categories, forming a hierarchical tree of around 14,000 categories in the WHO base classification and over 70,000 billable codes in the US clinical modification.

ICD-10 codes appear throughout healthcare data: electronic health records (EHRs), HL7 messages, FHIR Condition resources, insurance claims (CMS-1500, UB-04), cancer registries, public health surveillance feeds, and international cause-of-death reports. Validating them — both syntactically and against the current official dictionary — is essential for claim acceptance, interoperability, and data quality.


2. Code structure

An ICD-10 code has a well-defined prefix structure:

J45.0

Chapter letter

J

Respiratory system

Category

45

Asthma

Sub-category

0

Predominantly allergic

The first character is always a letter (A–Z, excluding U which is reserved by WHO for provisional use). The next two characters are digits forming the category (e.g. J45 = Asthma). An optional decimal point followed by one to four additional characters specifies sub-categories and clinical detail.

The chapter letter maps to broad classes of disease:

LetterRangeChapter
A–BA00–B99Certain infectious and parasitic diseases
C–DC00–D49Neoplasms
EE00–E89Endocrine, nutritional and metabolic diseases
FF01–F99Mental, behavioural and neurodevelopmental disorders
II00–I99Diseases of the circulatory system
JJ00–J99Diseases of the respiratory system
KK00–K95Diseases of the digestive system
OO00–O9APregnancy, childbirth and the puerperium
S–TS00–T88Injury, poisoning and other external causes
V–YV00–Y99External causes of morbidity
ZZ00–Z99Factors influencing health status

A few well-known codes:

CodeMeaning
A00.0Cholera due to Vibrio cholerae 01, biovar cholerae
E11.9Type 2 diabetes mellitus without complications
I10Essential (primary) hypertension
I21.9Acute myocardial infarction, unspecified
J45.0Predominantly allergic asthma
S72.001AFracture of unspecified part of neck of right femur, initial encounter (CM-only)
U07.1COVID-19, virus identified
Z00.00Encounter for general adult medical examination without abnormal findings

3. WHO ICD-10 vs ICD-10-CM

A common source of confusion: there is not one ICD-10 dataset but several national clinical modifications. The two most commonly encountered are:

WHO ICD-10

The base international classification, ~14,000 categories. Used for mortality reporting, epidemiology, and healthcare outside the United States. Codes have the form A00, A00.0 — digits after the decimal point.

ICD-10-CM (US)

The US Clinical Modification maintained by NCHS/CMS. A superset of WHO ICD-10 with over 70,000 highly granular codes for clinical and billing use. Adds alphanumeric sub-codes and extension characters (e.g. S06.0X1A).

ℹ️The IsValid /v0/icd10 endpoint accepts both forms with a permissive regex — A00, A00.0, and S06.0X1A all pass format validation. Dictionary lookup is backed by the NIH/NLM ICD-10-CM dataset, which is a superset covering both standards.

4. Why ICD-10 validation matters

Claim acceptance and reimbursement

Medical claims with invalid or outdated ICD-10 codes are rejected by payers, delaying reimbursement and adding administrative cost. Claim scrubbers run ICD-10 validation before submission to catch typos, decommissioned codes, and incorrect code-to-diagnosis combinations.

HL7 and FHIR interoperability

FHIR Condition resources reference ICD-10 codes via the http://hl7.org/fhir/sid/icd-10 code system. Exchanging patient data between EHRs, HIEs, and regulatory systems requires every code to be syntactically valid and registered in the current version of the classification.

Clinical data quality

Clinical dashboards, cohort selection, and registry submissions rely on accurate diagnosis codes. A small rate of invalid codes can distort quality metrics, miss patients from outcome studies, or trigger false-positive safety alerts.

Public health reporting

Cancer registries, notifiable disease surveillance, and cause-of-death reporting use ICD-10 codes for automated case detection. Invalid codes break downstream aggregation and can hide emerging health trends.


5. The right solution

The IsValid ICD-10 API validates both format and existence against a locally-maintained copy of the NIH/NLM ICD-10-CM dataset (refreshed monthly). It returns the diagnosis title, chapter, parent code, and leaf/billable flag.

70,000+
Codes
ICD-10-CM dictionary
<20ms
Response time
indexed lookup
100/day
Free tier
no credit card

Full parameter reference and response schema: ICD-10 Validation API docs →


6. Node.js code example

Validate a single ICD-10 code:

import { createClient } from '@isvalid-dev/sdk';

const iv = createClient({ apiKey: process.env.ISVALID_API_KEY });

// ── Validate an ICD-10 code ─────────────────────────────────────────────────

const result = await iv.icd10('J45.0');

if (!result.found) {
  console.log('Code is not in the ICD-10-CM dictionary');
} else {
  console.log('Title:', result.title);     // → 'Predominantly allergic asthma'
  console.log('Chapter:', result.chapter); // → 'J'
  console.log('Parent:', result.parent);   // → 'J45'
  console.log('Leaf:', result.isLeaf);     // → true (billable)
}

Expand a parent code into its children:

// Get all sub-categories of asthma (J45)
async function listChildren(parent) {
  const response = await fetch(
    `${BASE_URL}/v0/icd10/children?code=${encodeURIComponent(parent)}`,
    { headers: { Authorization: `Bearer ${API_KEY}` } },
  );
  return response.json();
}

const children = await listChildren('J45');

for (const c of children) {
  console.log(`  ${c.icd10} — ${c.title}`);
}
// → J45.0 Predominantly allergic asthma
// → J45.1 Nonallergic asthma
// → J45.2 Mild intermittent asthma
// ...

Typical use — validating a batch of diagnosis codes from an incoming claim:

// Validate every diagnosis on a claim before submission
async function scrubClaim(claim) {
  const results = await Promise.all(
    claim.diagnoses.map(async (dx) => {
      const r = await validateIcd10(dx.code);
      return { dx, valid: r.valid, found: r.found, title: r.title };
    }),
  );

  const errors = results
    .filter((r) => !r.valid || !r.found)
    .map((r) => `${r.dx.code}: ${!r.valid ? 'invalid format' : 'not in dictionary'}`);

  return { accepted: errors.length === 0, errors, annotated: results };
}
ICD-10 codes are case-insensitive. The API accepts j45.0 and J45.0, but always normalise to uppercase when storing to prevent duplicate keys in indexes.

7. cURL example

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/icd10?value=J45.0"

Validate an ICD-10-CM code with extension characters:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/icd10?value=S06.0X1A"

List child codes of a category:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/icd10/children?code=J45"

8. Understanding the response

Known code:

{
  "valid": true,
  "found": true,
  "icd10": "J45.0",
  "title": "Predominantly allergic asthma",
  "chapter": "J",
  "parent": "J45",
  "isLeaf": true,
  "source": "CMS",
  "version": "NLM-2026"
}

Valid format but unknown code:

{
  "valid": true,
  "found": false,
  "icd10": "J99.9",
  "title": null,
  "chapter": "J",
  "parent": null,
  "isLeaf": null,
  "source": null,
  "version": null
}

Invalid format:

{
  "valid": false
}
FieldTypeDescription
validbooleanWhether the code matches the ICD-10 / ICD-10-CM format regex
foundbooleanWhether the code exists in the ICD-10-CM dictionary
icd10stringNormalised input code
titlestring | nullDiagnosis description
chapterstring | nullChapter letter (A–Z)
parentstring | nullParent code in the hierarchy
isLeafboolean | nullTrue if the code has no children (billable)
sourcestring | nullDataset source (CMS)
versionstring | nullDataset release identifier

9. Edge cases

Dotted vs flat code form

Some legacy systems emit ICD-10 codes without the decimal point (e.g. J450 instead of J45.0). The API accepts both forms and returns the canonical dotted form in the icd10 field.

Header vs billable codes

Non-leaf codes like J45 are parent/header codes — they describe a category but cannot be used for billing in the US. Use the isLeaf field to distinguish. Claim scrubbers should reject header codes on US claims even when found: true.

Deprecated codes

CMS retires and adds codes annually (effective October 1). A code valid in FY2024 may not appear in FY2026. When processing historical data, the dictionary version in the response (version field) tells you which release was used for validation.

ICD-10 vs ICD-10-CM

Codes beyond 3 digits after the decimal, or with alphabetic characters after the decimal (e.g. S06.0X1A), exist only in US ICD-10-CM. If your context is non-US WHO ICD-10, reject codes longer than X00.0 or containing letters after the decimal even when the API returns found: true.

⚠️The regex is permissive by design — it accepts the union of WHO ICD-10 and ICD-10-CM. Apply a stricter downstream filter if you need WHO-only codes.

Summary

Validate both format and existence — a syntactically correct code may not be in the current dictionary
Use isLeaf to distinguish billable codes from parent/header categories
Normalise input to uppercase and preserve the decimal when storing
Record the dictionary version alongside the validation result for auditable claim history
Do not rely on regex-only validation — dictionary lookup catches decommissioned codes
Do not assume WHO ICD-10 and ICD-10-CM are interchangeable — CM is a US-only superset

Node.js integration notes

In a TypeScript project, model a validated ICD-10 code as a branded type — type Icd10 = string & { readonly __brand: 'Icd10' } — so the compiler enforces that only checked values flow through your claim pipeline. The IsValid SDK ships with full TypeScript definitions, giving you autocomplete on every response field without manual type declarations.

For Express.js or Fastify services that accept diagnosis codes as query or path parameters, add a middleware that validates the value before the route handler runs. On success, attach the full response to req.validatedData so handlers can use title, chapter, and isLeaf without a second API call.

For claim scrubbers processing thousands of codes per second, cache API responses in Redis keyed by the normalised code. A one-day TTL is safe; the dictionary changes at most annually. Use Promise.allSettled() to validate all diagnoses on a claim in parallel and collect all errors at once rather than failing on the first bad code.

See also

Validate ICD-10 codes instantly

Free tier includes 100 API calls per day. No credit card required. Validate against a locally-maintained copy of the NIH/NLM ICD-10-CM dictionary.