ICD-11 Validation in Python — WHO MMS Diagnosis Codes
ICD-11 is the WHO's successor to ICD-10 — a digital-first classification in effect since 2022 that is gradually replacing ICD-10 for mortality and morbidity reporting worldwide. Here's how ICD-11 MMS codes are structured, what changed from ICD-10, and how to validate them in Python with the IsValid API.
In this guide
1. What is ICD-11?
ICD-11 is the 11th revision of the International Classification of Diseases, adopted by the World Health Assembly in 2019 and in official use since 1 January 2022. ICD-11 is a digital-native classification — a web-based ontology (the Foundation Component) from which multiple linearizations are derived.
The primary linearization is MMS — Mortality and Morbidity Statistics — which serves the role that ICD-10 filled: a flat list of stem codes for reporting, billing, and statistical analysis. MMS has about 17,000 categories across 28 chapters, with new chapters for traditional medicine and extension codes.
Adoption is gradual — as of 2026, most member states are still in the transition period. Many jurisdictions have set target dates between 2025 and 2030 for full ICD-11 implementation; systems commonly produce both ICD-10 and ICD-11 codes in parallel during the migration.
2. MMS stem code structure
An ICD-11 MMS stem code looks like this:
Chapter
1
Infectious diseases
Block
A
Gastrointestinal
Category
00
Cholera
The first character is a digit 1–9 identifying the chapter (or V / X for supplementary and extension chapters). Subsequent characters are alphanumeric, with letters I and O excluded to prevent confusion with digits. An optional decimal + one or two characters specifies sub-categories.
| Code | Meaning |
|---|---|
| 1A00 | Cholera |
| 2B5A | Breast cancer |
| 5A11 | Type 2 diabetes mellitus |
| 6A00 | Disorders of intellectual development |
| BA00 | Essential hypertension |
| CA23 | Asthma |
| RA01 | COVID-19 |
3. ICD-10 vs ICD-11
| Aspect | ICD-10 | ICD-11 |
|---|---|---|
| Year adopted | 1990 | 2019 (in effect 2022) |
| Code format | Letter + digits (+ decimal) | Digit + alphanum (+ decimal) |
| Chapters | 22 | 28 |
| Categories | ~14,000 (WHO base) | ~17,000 (MMS) |
| Structure | Flat tabular | Ontology-based, multi-linearization |
| Post-coordination | Limited | First-class (with extension codes) |
| API access | File downloads | WHO ICD-API (OAuth) |
4. Why ICD-11 validation matters
Parallel ICD-10 / ICD-11 systems
During the transition, many systems produce or consume both ICD-10 and ICD-11 codes. Validation distinguishes the two (formats are non-overlapping) and routes codes to the correct downstream processor.
FHIR Condition resources
FHIR supports ICD-11 via the http://id.who.int/icd/release/11/mms code system. Invalid codes break cross-system interoperability and are rejected by conformant validators.
WHO reporting and surveillance
Countries report mortality and morbidity statistics to WHO using ICD-11 codes. Invalid codes cause rejections at the WHO submission portal.
Research datasets
Clinical research increasingly uses ICD-11 for international cohort studies. Syntactically-valid but unknown codes often indicate OCR or transcription errors that would otherwise silently corrupt analysis results.
5. The right solution
The IsValid ICD-11 API validates format with a strict regex and performs dictionary lookup against a locally-maintained mirror of the current WHO ICD-11 MMS linearization (refreshed monthly from the WHO ICD-API).
Full parameter reference: ICD-11 Validation API docs →
6. Python code example
Install with pip install isvalid-sdk or pip install requests.
# icd11_validator.py import os from isvalid_sdk import IsValidConfig, create_client iv = create_client(IsValidConfig(api_key=os.environ["ISVALID_API_KEY"])) # ── Validate an ICD-11 MMS code ───────────────────────────────────────────── result = iv.icd11("1A00") if not result["found"]: print("Code is not in the WHO ICD-11 MMS dictionary") else: print(f"Title: {result['title']}") # → 'Cholera' print(f"Chapter: {result['chapter']}") # → '01' print(f"Foundation URI: {result['foundationUri']}") # → WHO foundation link print(f"Version: {result['version']}")
Routing a mixed ICD-10 / ICD-11 stream based on the first character:
# ICD-10 starts with a LETTER, ICD-11 starts with a DIGIT. # Delegate validation to the right endpoint. def validate_diagnosis(code: str) -> dict: first = code.strip()[:1] if first.isdigit(): return {"revision": "ICD-11", **validate_icd11(code)} return {"revision": "ICD-10", **validate_icd10(code)} print(validate_diagnosis("J45.0")) # → ICD-10 print(validate_diagnosis("CA23")) # → ICD-11
I and O are never valid — WHO excluded them to prevent confusion with digits 1 and 0.7. cURL example
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/icd11?value=1A00"
Validate a circulatory code:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/icd11?value=BA00"
8. Understanding the response
Known code:
{ "valid": true, "found": true, "icd11": "1A00", "title": "Cholera", "chapter": "01", "parent": null, "isLeaf": false, "foundationUri": "http://id.who.int/icd/entity/257068234", "blockId": null, "version": "ICD-11 for Mortality and Morbidity Statistics" }
Valid format but unknown code:
{ "valid": true, "found": false, "icd11": "9ZZ9", "title": null, "chapter": null, "parent": null, "isLeaf": null, "foundationUri": null, "blockId": null, "version": null }
Invalid format:
{ "valid": false }
| Field | Type | Description |
|---|---|---|
| valid | bool | Whether the code matches the ICD-11 MMS stem regex |
| found | bool | Whether the code exists in the WHO ICD-11 MMS dictionary |
| icd11 | str | Normalised input code |
| title | str | None | Entity title |
| chapter | str | None | Chapter number |
| isLeaf | bool | None | True if the code has no child entities |
| foundationUri | str | None | WHO foundation URI for the entity |
| version | str | None | MMS release version |
9. Edge cases
Letters I and O are reserved
WHO excludes I and O from stem codes. Any code containing either letter fails the regex.
Post-coordination
ICD-11 supports combining codes via the & separator (e.g. CA23.3&XB25). Split on & before validating each stem code individually:
expression = "CA23.3&XB25" parts = expression.split("&") results = [validate_icd11(p) for p in parts] all_valid = all(r["valid"] and r["found"] for r in results)
Chapter V and Chapter X
Extension chapters V (functioning) and X (extension codes) use letter prefixes. Verify chapter context in the response chapter field.
Version drift
WHO publishes annual MMS releases. The version field in the response records which release was used for dictionary lookup; log it with each validation for auditability.
Summary
Python integration notes
In typed Python projects, model ICD-10 and ICD-11 as distinct NewType aliases so type checkers prevent accidental cross-revision comparison. A Pydantic Union[Icd10, Icd11] discriminated by the first character is useful when storing mixed data during migration periods.
Because the first character unambiguously distinguishes the two revisions, a cheap local dispatch check can route codes to the right endpoint without an extra network call: code[0].isdigit() → ICD-11, otherwise ICD-10.
Use httpx.AsyncClient for concurrent validation of batches and cache responses in Redis keyed by normalised code. A one-day TTL is appropriate — WHO publishes annual releases, so the dictionary is effectively static within a year.
- Read
os.environ["ISVALID_API_KEY"]at startup and fail fast if missing - Use
respxto mock the IsValid client in unit tests — never call the real API in CI - For FastAPI services, expose ICD validation as a dependency so every endpoint automatically benefits from the pre-validated metadata
- Record
versionin your audit log so you can prove which MMS release validated each historical record
See also
Validate ICD-11 codes instantly
Free tier includes 100 API calls per day. Validates against the current WHO ICD-11 MMS linearization.