How to Look Up NCCI Workers Compensation Class Codes Programmatically
Every medical claim submitted to Medicare goes through the National Correct Coding Initiative (NCCI) edit system before payment is approved. CMS publishes tens of thousands of Procedure-to-Procedure (PTP) edits and Medically Unlikely Edits (MUE) that define which CPT/HCPCS code pairs can be billed together and how many units of a given code are reasonable per encounter. If your billing system does not check claims against these edits before submission, you are going to get denials.
This article explains what NCCI edits are, how PTP bundling and MUE limits work, and how to validate claims programmatically.
What are NCCI edits
The NCCI was established by CMS in 1996 to promote correct coding and prevent improper payment for Medicare Part B claims. There are two types of edits:
PTP (Procedure-to-Procedure) edits define pairs of CPT/HCPCS codes that should not normally be billed together on the same claim. One code in the pair is the "comprehensive" code (the broader procedure) and the other is the "component" code (a procedure that is considered part of the comprehensive one). For example, if a surgeon performs a total knee replacement, certain ancillary procedures performed during the same session are bundled into the primary code and should not be billed separately.
MUE (Medically Unlikely Edits) set the maximum number of units that can be reported for a single CPT/HCPCS code per line, per day, or per encounter. An MUE of 1 for a bilateral procedure means you cannot bill 3 units of that code on a single claim line without triggering a denial.
CMS publishes updated NCCI edit files quarterly. Each quarterly release adds, modifies, or deletes edit pairs. A code pair that was billable together last quarter may not be this quarter.
The modifier indicator
Not every PTP edit is an absolute block. Each edit has a modifier indicator that determines whether the bundling can be overridden:
- Modifier Indicator 0: Not allowed. No modifier will unbundle this pair. The component code simply cannot be billed with the comprehensive code.
- Modifier Indicator 1: Modifier allowed. If the services are truly distinct (different anatomic site, different encounter, different practitioner), you can append modifier 25, 59, XE, XS, XP, or XU to the component code to unbundle the edit.
- Modifier Indicator 9: Not applicable.
The -59 modifier and the newer X{ESPU} modifiers are the most commonly used unbundling modifiers. CMS introduced the X modifiers (XE, XS, XP, XU) to provide more specificity than the broad -59, and many payers now prefer them.
Why this matters for billing teams
The financial impact of NCCI edits is significant:
- Denied claims cost money to rework and resubmit. The average cost to rework a denied claim is $25-$50.
- Improper unbundling -- billing codes separately that should be bundled -- is one of the top reasons for Medicare audits. OIG recoveries for unbundling violations run in the millions annually.
- MUE violations are an automatic denial. If the MUE for a code is 2 and you bill 3 units, the excess units are denied with no appeal path.
- Quarterly updates mean your edit logic must stay current. A code pair that was clean in Q1 might have a new edit in Q2.
Validating a code pair
The MCP server @easysolutions906/ncci-api embeds the full CMS NCCI PTP edit table and MUE data, updated quarterly.
Check if two codes can be billed together
Validating codes 99213 (office visit) and 36415 (venipuncture):
{
"code1": "99213",
"code2": "36415",
"canBillTogether": false,
"hasEdit": true,
"comprehensiveCode": "99213",
"componentCode": "36415",
"modifierIndicator": 1,
"modifierIndicatorDescription": "Modifier allowed — use modifier 25, 59, XE, XS, XP, or XU to unbundle",
"modifierApplied": null,
"unbundledByModifier": false,
"rationale": "Standards of medical/surgical practice",
"message": "NCCI edit: 99213 bundles 36415. Apply modifier 25/59/XE/XS/XP/XU to 36415 if services are distinct."
}
The response tells you exactly what is happening: 99213 is the comprehensive code, 36415 is the component, and modifier indicator 1 means you can unbundle with the appropriate modifier. If the venipuncture was for a separately identifiable service, appending modifier 59 to 36415 resolves the edit.
Applying a modifier to unbundle
If modifiers are included in the request, the API evaluates whether they resolve the edit:
{
"code1": "99213",
"code2": "36415",
"canBillTogether": true,
"hasEdit": true,
"comprehensiveCode": "99213",
"componentCode": "36415",
"modifierIndicator": 1,
"modifierApplied": ["59"],
"unbundledByModifier": true,
"message": "Edit exists but unbundled by modifier 59 on 36415. These codes can be billed together."
}
This is the key workflow: check the pair, see if an edit exists, check the modifier indicator, and if modifier is allowed, apply the correct one.
Validating a full claim
Real claims have more than two codes. The ncci_validate_claim tool checks every code pair combination on a claim and also verifies MUE limits.
Submitting a claim with codes 99213, 36415, 80053, and 85025:
{
"codesSubmitted": ["99213", "36415", "80053", "85025"],
"pairsChecked": 6,
"editIssues": 2,
"mueIssues": 0,
"blocked": 2,
"unbundled": 0,
"clean": false,
"issues": [
{
"code1": "99213",
"code2": "36415",
"canBillTogether": false,
"comprehensiveCode": "99213",
"componentCode": "36415",
"modifierIndicator": 1
},
{
"code1": "80053",
"code2": "85025",
"canBillTogether": false,
"comprehensiveCode": "80053",
"componentCode": "85025",
"modifierIndicator": 0
}
],
"summary": "Claim has 2 blocked edit pair(s) and 0 MUE violation(s)."
}
The first issue (99213/36415) can be resolved with a modifier. The second issue (80053/85025) has modifier indicator 0, meaning it cannot be unbundled -- one of those codes must be removed from the claim.
Looking up MUE limits
The ncci_mue tool returns the maximum units allowed for a code:
{
"code": "99213",
"found": true,
"description": "Office or other outpatient visit",
"practitionerMue": 1,
"facilityMue": 1,
"rationale": "Nature of Service/Procedure",
"adjudicationIndicator": 2,
"adjudicationDescription": "Per Day Edit — applies per beneficiary per day"
}
An MUE of 1 with adjudication indicator 2 means this code can only be billed once per beneficiary per day. Submitting 2 units on the same date of service will trigger an automatic denial.
The adjudication indicator matters:
- 1 (Claim Line Edit): The limit applies per claim line. You cannot split the units across multiple lines to avoid the edit.
- 2 (Per Day): The limit applies per beneficiary per day, across all claim lines.
- 3 (Per Encounter): The limit applies per encounter, which is more restrictive than per day.
Browsing edits for a code
The ncci_edits tool returns all PTP edits associated with a specific code:
{
"code": "99213",
"editCount": 47,
"edits": [
{
"pairedCode": "36415",
"role": "comprehensive",
"modifierIndicator": 1,
"rationale": "Standards of medical/surgical practice",
"pairedCodeDescription": "Collection of venous blood by venipuncture"
},
{
"pairedCode": "36416",
"role": "comprehensive",
"modifierIndicator": 1,
"rationale": "Standards of medical/surgical practice",
"pairedCodeDescription": "Collection of capillary blood specimen"
}
]
}
This is useful for building billing rules engines or populating a reference table in your practice management system.
Searching edits by keyword
The ncci_search tool lets you search across the entire edit database by code, procedure name, or category:
{
"query": "arthroscopy",
"ptpEdits": {
"total": 312,
"results": [...]
},
"mue": {
"total": 24,
"results": [...]
}
}
Setting up the MCP server
Add to your Claude Desktop or Cursor configuration:
{
"mcpServers": {
"ncci": {
"command": "npx",
"args": ["-y", "@easysolutions906/ncci-api"]
}
}
}
After restarting, you can ask natural language questions like:
- "Can I bill 99213 and 36415 together?"
- "What is the MUE limit for 99213?"
- "Show all NCCI edits for CPT 27447"
- "Validate this claim: 99213, 36415, 80053, 85025"
- "Will modifier 59 on 36415 unbundle the edit with 99213?"
The server exposes five tools: ncci_validate_pair, ncci_validate_claim, ncci_edits, ncci_mue, and ncci_search.
Practical integration example
Here is a common pattern for a claims scrubber that checks a claim before submission:
const scrubClaim = async (codes, modifiers = {}) => {
const res = await fetch('https://your-api-url.com/validate/claim', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NCCI_API_KEY,
},
body: JSON.stringify({ codes, modifiers }),
});
const result = await res.json();
if (result.clean) {
return { pass: true, message: 'Claim passes NCCI validation' };
}
const actionItems = result.issues
.filter((issue) => !issue.canBillTogether)
.map((issue) => {
if (issue.modifierIndicator === 1) {
return `Add modifier 59/XE/XS/XP/XU to ${issue.componentCode} to unbundle from ${issue.comprehensiveCode}`;
}
return `Remove ${issue.componentCode} — it cannot be billed with ${issue.comprehensiveCode} (no modifier override)`;
});
const mueItems = result.mue.map((m) =>
`Reduce ${m.code} from ${m.unitsOnClaim} units to ${m.mueLimit} (MUE limit)`
);
return {
pass: false,
actionItems: [...actionItems, ...mueItems],
};
};
// Check a claim before submission
const result = await scrubClaim(
['99213', '36415', '80053'],
{ '36415': '59' }
);
// { pass: true, message: 'Claim passes NCCI validation' }
Run this before every claim submission. Flag blocked pairs for coder review, auto-suggest modifiers where indicator 1 allows it, and hard-stop any MUE violations.
Batch validation
For high-volume billing operations, the REST API supports batch validation of multiple claims in a single request:
const batchScrub = async (claims) => {
const res = await fetch('https://your-api-url.com/validate/batch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.NCCI_API_KEY,
},
body: JSON.stringify({ claims }),
});
const { results } = await res.json();
const flagged = results.filter((r) => !r.clean);
return {
total: results.length,
clean: results.length - flagged.length,
flagged: flagged.length,
details: flagged,
};
};
// Scrub an entire day's claims
const dayResults = await batchScrub([
{ codes: ['99213', '36415'], modifiers: { '36415': '59' } },
{ codes: ['27447', '27486'] },
{ codes: ['99214', '80053', '85025'] },
]);
Data freshness
CMS publishes NCCI edit updates quarterly (January, April, July, October). Each update can add new edits, delete existing ones, or change modifier indicators. The @easysolutions906/ncci-api package includes a data-info endpoint that returns the CMS quarter, build date, and record counts so you can verify the data is current. The embedded data is rebuilt from CMS source files with each package update.
NCCI validation is one of those problems that every medical billing system needs to solve but few handle well. The edit tables are large, the quarterly updates are easy to miss, and the modifier logic has enough nuance that getting it wrong costs real money in denials and rework. Having the full CMS edit dataset available as both MCP tools and a REST API means you can integrate claims scrubbing wherever it is needed -- inside an AI coding assistant, a practice management system, or a standalone claims review workflow.
Top comments (0)