A developer's guide to integrating medical coding capabilities

TL;DR
- Before building, nail two things early: specify care setting (inpatient vs. outpatient rules differ significantly) and decide which code systems you need, since a single request can cover up to four simultaneously.
- The codes/candidates split is the key design difference: codes are what should be billed given clinical context and guidelines, candidates are what was present but should be excluded, mirroring how a trained coder actually works and reducing overcoding risk.
- Every prediction includes traceable evidence spans and an alternatives array, giving compliance teams a self-documenting audit trail without any additional reconstruction work after the fact.
What to know before you build, and how Symphony for Medical Coding makes it straightforward
Medical coding has a reputation as one of the harder problems to embed in a healthcare product. The rules are complex, the code systems are large, and most existing solutions were built for health systems procurement teams, not developers. This guide covers what you need to understand before you build, and how to integrate Corti's Symphony for Medical Coding via a single API call.
The planning stage
A few decisions shape everything downstream and getting them right early saves significant rework.
Care setting matters more than most developers expect. Inpatient and outpatient encounters follow different coding guidelines. A condition that should be coded in a hospital admission may be excluded in an outpatient clinic visit, and vice versa. Systems that do not distinguish between the two are applying the wrong rules to a meaningful portion of predictions. Symphony requires you to specify care setting at the request level, with separate systems for icd10cm-inpatient and icd10cm-outpatient. This is by design.
Decide which code systems you need. Symphony supports ICD-10-CM (diagnosis coding for both inpatient and outpatient), ICD-10-PCS (inpatient procedure coding), and CPT (outpatient procedure coding). A single request can include up to four systems simultaneously, so you are not forced to make separate calls for diagnosis and procedure codes.
Think about filtering early. If your product serves a specific specialty, you can restrict predictions to relevant code ranges. A neurosurgery workflow does not need obstetrics codes surfaced. Filtering makes the task easier for the model and reduces noise for the end user. This is handled via the optional filter parameter in the request body.
Making your first request
The endpoint is POST /tools/coding/. At minimum, a request requires three things: a system array specifying which code systems to predict, a context array providing the clinical text, and the Tenant-Name header identifying your account.
{
"system": ["icd10cm-outpatient", "cpt"],
"context": [
{
"type": "text",
"text": "Patient presents with type 2 diabetes mellitus with diabetic chronic kidney disease, stage 3. Current medications include metformin and lisinopril. Blood pressure elevated at 148/92."
}
]
}
The response returns two distinct arrays: codes and candidates.
codes are predictions the model is confident should be coded given the clinical context and applicable guidelines. These are the codes that should be coded, not just every condition mentioned.
candidates are codes the model identified as clinically present but determined should not be coded based on guidelines. A condition documented as historical, incidental, or not affecting the current encounter may appear here rather than in codes. This distinction maps directly to how trained coders work: they identify everything in the note, then apply rules to determine what to include.
This two-list structure is one of the most meaningful design differences between Symphony and generic LLM approaches. A model that simply returns everything it finds produces overcoding risk. Symphony surfaces the reasoning, not just the result.
Reading the evidence
Every prediction in both codes and candidates includes an evidences array. Each evidence object contains three things: the exact text span from the input that triggered the prediction, the character offsets locating that span in the original text, and a contextIndex mapping back to the input context array.
"evidences": [
{
"contextIndex": 0,
"text": "type 2 diabetes mellitus with diabetic chronic kidney disease, stage 3",
"start": 21,
"end": 91
}
]
This is the audit trail. Every code can be traced back to the clinical language that generated it. For products that need to support compliance review, coder override workflows, or payer audit defense, this traceability is not optional. It is what makes the output defensible.
Each prediction also includes an alternatives array listing other codes the model considered before selecting the final prediction. This gives reviewers visibility into the model's reasoning rather than a black box result.
Handling the response in your product
How you surface predictions depends on your workflow, but a few patterns are worth thinking through.
For human-in-the-loop workflows, codes and candidates map naturally to different UI treatments. Predicted codes can be pre-selected for coder review, with candidates visible but unselected. The evidence spans can be used to highlight relevant text in the clinical note alongside each suggestion, making review fast rather than effortful.
For fully automated workflows, the codes array is your primary output. The evidence and alternatives give you the material to build audit logs that satisfy compliance requirements without additional reconstruction work.
For specialty-focused applications, the filter parameter lets you scope predictions to relevant code families at request time. This is more reliable than post-processing the response to remove irrelevant codes, because it shapes the model's reasoning rather than just filtering what comes back.
A note on what Symphony handles differently
Most coding tools were built on one of two approaches: rule-based dictionary matching, which fails on context and synonyms, or ML models trained on annotated clinical data, which degrade on rare codes and require retraining every October when ICD codes update.
Symphony uses neither. The architecture encodes coding logic directly rather than learning patterns from historical data. This means rare codes are handled with the same reliability as common ones, predictions stay current through ICD update cycles without retraining, and the model generalizes across specialties and geographies without requiring annotated data from each new context.
For developers, the practical consequence is that you can integrate once and expect consistent behavior across code types, care settings, and clinical specialties. You are not building against a model that will degrade the first time a patient presents with an unusual condition, or the first October after you ship.
Getting started
The /tools/coding/ endpoint is live with support for ICD-10-CM, ICD-10-PCS, and CPT. Full API documentation, authentication setup, and use case guides are available in the Corti developer docs.
The fastest path to production is to start with a single care setting, a defined set of code systems relevant to your workflow, and real clinical text from your target use case. Evidence-based output and the codes/candidates distinction become immediately clear once you see them against actual notes.
Next in this series: AI-native entrants in RCM. A look at the landscape of companies building in the space and where infrastructure fits.
More guides to explore
Build faster. Ship safer. Scale smarter.
Get started with healthcare-native APIs built to power real clinical workflows.


