Adding ICD-10 Code Search to Your Healthcare Application
Every healthcare application that submits claims, generates clinical documentation, or reports quality measures needs ICD-10 codes. If you are building an EHR, a patient intake system, a billing platform, or a clinical decision support tool, you need a way to search and validate diagnosis codes. The CMS 2025 code set contains 74,260 codes. Embedding that into a searchable, fast API endpoint is not trivial.
This article walks through integrating ICD-10 code search into a patient intake form: autocomplete search as the user types, code validation on form submission, and chapter-level categorization for reporting.
The problem with existing solutions
Most healthcare developers either download the CMS text files and parse them into a database, use the bulky UMLS API (which requires a license agreement and has aggressive rate limits), or hard-code a subset of common codes. None of these are great:
- Self-hosted databases require schema design, import scripts, and annual updates when CMS publishes new codes every October
- UMLS/NLM APIs are slow, rate-limited, and require institutional credentials
- Hard-coded subsets inevitably miss the code your users need
The ICD-10 API embeds all 74,260 CMS 2025 codes locally, indexes them for fast text search, and returns results in under 50ms.
Searching by symptom description
Your intake form needs an autocomplete that searches by symptom or condition name. Here is the API call:
curl "https://icd10-api-production.up.railway.app/search?q=chest+pain&limit=5"
Response:
{
"query": "chest pain",
"total": 18,
"results": [
{
"code": "R07.9",
"description": "Chest pain, unspecified",
"chapter": 18,
"chapterTitle": "Symptoms, signs and abnormal clinical and laboratory findings",
"billable": true
},
{
"code": "R07.1",
"description": "Chest pain on breathing",
"chapter": 18,
"chapterTitle": "Symptoms, signs and abnormal clinical and laboratory findings",
"billable": true
},
{
"code": "R07.89",
"description": "Other chest pain",
"chapter": 18,
"chapterTitle": "Symptoms, signs and abnormal clinical and laboratory findings",
"billable": true
}
]
}
The billable field tells you whether the code is specific enough for claims submission. Non-billable codes (category headers) need to be drilled down further.
Building the autocomplete in JavaScript
Here is a React-style autocomplete component that searches as the user types:
const searchICD10 = async (query) => {
if (query.length < 2) return [];
const res = await fetch(
`https://icd10-api-production.up.railway.app/search?q=${encodeURIComponent(query)}&limit=10`
);
const data = await res.json();
return data.results.map((r) => ({
code: r.code,
label: `${r.code} - ${r.description}`,
billable: r.billable,
}));
};
// Debounced search on keystroke
let timeout;
const onInputChange = (value) => {
clearTimeout(timeout);
timeout = setTimeout(async () => {
const results = await searchICD10(value);
renderSuggestions(results);
}, 300);
};
Validating codes on form submission
Before submitting a claim, validate that the selected code exists and is billable:
const validateDiagnosisCode = async (code) => {
const res = await fetch(
`https://icd10-api-production.up.railway.app/validate?code=${encodeURIComponent(code)}`
);
const data = await res.json();
if (!data.valid) {
return { ok: false, error: `Invalid ICD-10 code: ${code}` };
}
if (!data.billable) {
return {
ok: false,
error: `${code} is a category header, not a billable code. Please select a more specific code.`,
};
}
return { ok: true, code: data.code, description: data.description };
};
// On form submission
const handleSubmit = async (formData) => {
const diagnosisValidation = await validateDiagnosisCode(formData.diagnosisCode);
if (!diagnosisValidation.ok) {
showError(diagnosisValidation.error);
return;
}
await submitClaim({
...formData,
diagnosisCode: diagnosisValidation.code,
diagnosisDescription: diagnosisValidation.description,
});
};
Looking up a specific code
When you have a code and need its details:
curl "https://icd10-api-production.up.railway.app/lookup?code=E11.9"
{
"code": "E11.9",
"description": "Type 2 diabetes mellitus without complications",
"formatted": "E11.9",
"chapter": 4,
"chapterTitle": "Endocrine, nutritional and metabolic diseases",
"chapterRange": "E00-E89",
"billable": true,
"valid": true
}
This is useful for displaying human-readable diagnosis names in patient records, discharge summaries, and encounter histories.
Batch validation for claims processing
If your billing system processes batches of claims, validate all diagnosis codes at once:
curl -X POST https://icd10-api-production.up.railway.app/validate/batch \
-H 'Content-Type: application/json' \
-d '{"codes": ["E11.9", "J06.9", "INVALID", "M54.5"]}'
The response tells you which codes are valid, which are invalid, and which are non-billable category headers -- before you submit to the payer and get rejections.
Using the MCP server for clinical workflows
The healthcare MCP server (@easysolutions906/mcp-healthcare) includes ICD-10 as one of 10 tools alongside NPI lookup, NDC drug search, and DEA validation. Install it for Claude Desktop:
{
"mcpServers": {
"healthcare": {
"command": "npx",
"args": ["-y", "@easysolutions906/mcp-healthcare"]
}
}
}
Then ask Claude: "What is the ICD-10 code for type 2 diabetes with diabetic retinopathy?" It will search the full code set and return the specific billable code. This is useful for clinical coders, medical billers, and developers testing their integrations without memorizing code ranges.
Data freshness
The ICD-10 code set is updated annually by CMS every October. The API embeds the CMS 2025 code set (74,260 codes) and will update when the 2026 set is published. Hit the /data-info endpoint to check the build date and record count at any time.
Getting started
- Search codes:
GET /search?q=diabetes&limit=10 - Look up a code:
GET /lookup?code=E11.9 - Validate a code:
GET /validate?code=E11.9 - Batch validate:
POST /validate/batchwith{"codes": [...]} - MCP server:
npx @easysolutions906/mcp-healthcare
No API key required. The dataset is public CMS data, and the API is free to use.
Top comments (0)