DEV Community

easysolutions906
easysolutions906

Posted on

How to Look Up NCCI Workers Compensation Class Codes Programmatically

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."
}
Enter fullscreen mode Exit fullscreen mode

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."
}
Enter fullscreen mode Exit fullscreen mode

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)."
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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": [...]
  }
}
Enter fullscreen mode Exit fullscreen mode

Setting up the MCP server

Add to your Claude Desktop or Cursor configuration:

{
  "mcpServers": {
    "ncci": {
      "command": "npx",
      "args": ["-y", "@easysolutions906/ncci-api"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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' }
Enter fullscreen mode Exit fullscreen mode

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'] },
]);
Enter fullscreen mode Exit fullscreen mode

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)