NPI Validation in Node.js — US Healthcare Provider IDs
National Provider Identifiers (NPIs) are 10-digit codes that uniquely identify healthcare providers in the United States. Here's how the Luhn check-digit algorithm works with the 80840 prefix and how to validate — and optionally look up — any NPI in production.
In this guide
1. What is an NPI?
A National Provider Identifier (NPI) is a unique 10-digit identification number issued by the Centers for Medicare & Medicaid Services (CMS) to healthcare providers in the United States. Mandated by the Health Insurance Portability and Accountability Act (HIPAA) of 1996, NPIs replaced the patchwork of provider identifiers that different health plans previously used.
Every healthcare provider who transmits health information electronically must have an NPI. This includes:
- Individual providers — physicians, dentists, nurses, therapists, pharmacists
- Organizational providers — hospitals, clinics, laboratories, pharmacies, nursing facilities
- Billing services — any entity that submits electronic claims on behalf of providers
NPIs are used in every HIPAA-covered transaction: claims submission, eligibility inquiries, referral authorizations, and remittance advice. An invalid NPI on a claim will result in an immediate rejection by the payer.
2. NPI anatomy — the 10-digit structure
Every NPI is exactly 10 digits long. Unlike many other identifiers, the digits themselves do not encode geographic or specialty information — they are assigned sequentially from a single national pool.
Positions 1–9 (identifier digits)
The first nine digits form the provider's unique identifier. They are assigned sequentially by the National Plan and Provider Enumeration System (NPPES) and carry no inherent meaning about the provider's type, location, or specialty.
Position 10 (check digit)
The 10th digit is a check digit computed using the Luhn algorithm with a special twist: the constant prefix 80840 is prepended to the 9 identifier digits before the Luhn calculation. This prefix identifies NPIs as part of the ISO standard for healthcare identifiers.
The 80840 prefix
The prefix 80 is the ISO 7812 industry code for healthcare, and 840 is the ISO 3166 country code for the United States. Together, 80840 ensures that NPIs are globally unique within the international healthcare identifier namespace.
3. The Luhn algorithm with 80840 prefix — step by step
NPI validation uses the standard Luhn algorithm, but the input is formed by prepending 80840 to all 10 NPI digits, creating a 15-digit number. The Luhn checksum of this 15-digit number must be divisible by 10. Let's walk through 1003000126:
Step 1 — Form the 15-digit number
80840 + 1003000126 = 808401003000126
Step 2 — Apply the Luhn algorithm
Starting from the rightmost digit, double every second digit. If the doubled value exceeds 9, subtract 9. Then sum all digits.
| Digits | 8 | 0 | 8 | 4 | 0 | 1 | 0 | 0 | 3 | 0 | 0 | 0 | 1 | 2 | 6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Double? | no | yes | no | yes | no | yes | no | yes | no | yes | no | yes | no | yes | no |
Step 3 — Check the sum
8 + 0 + 8 + 8 + 0 + 2 + 0 + 0 + 3 + 0 + 0 + 0 + 1 + 4 + 6 = 40 → 40 mod 10 = 0 ✓
The sum is divisible by 10, so the NPI check digit is valid.
Here's the algorithm implemented in JavaScript:
// npiCheckDigit.js — NPI Luhn validation with 80840 prefix function isValidNpi(npi) { if (!/^\d{10}$/.test(npi)) return false; // Prepend the 80840 prefix to form a 15-digit number const full = '80840' + npi; const digits = full.split('').map(Number); let sum = 0; let double = false; // Process from right to left (standard Luhn) for (let i = digits.length - 1; i >= 0; i--) { let d = digits[i]; if (double) { d *= 2; if (d > 9) d -= 9; } sum += d; double = !double; } return sum % 10 === 0; } console.log(isValidNpi('1003000126')); // true console.log(isValidNpi('1003000127')); // false — bad check digit
4. Why NPI validation matters
HIPAA compliance
HIPAA requires all covered entities to use NPIs in standard electronic transactions. Submitting claims with invalid or incorrect NPIs violates HIPAA transaction standards and can result in compliance penalties, audit flags, and delayed reimbursements.
Claims rejection
Health plans and clearinghouses validate NPIs at the point of claim submission. An invalid NPI — whether structurally incorrect or not found in the NPPES registry — triggers an immediate rejection (error code "Invalid/Missing Provider Identifier"). Validating NPIs before submission reduces rejection rates and speeds up revenue cycles.
Provider credentialing
During provider enrollment and credentialing, verifying an NPI against the NPPES registry confirms the provider's identity, taxonomy (specialty), and current enrollment status. This is critical for network adequacy checks and fraud prevention.
Fraud detection
Deactivated or invalid NPIs on claims can indicate billing fraud. Cross-referencing the NPI against the NPPES registry helps detect providers who have been excluded from federal healthcare programs or whose credentials have been revoked.
5. The right solution
The IsValid NPI API validates the Luhn checksum and optionally looks up the NPI in the NPPES registry in a single GET request. With the lookup=true parameter, the response includes the provider's name, type, credential, taxonomy, address, and enrollment status.
Get your free API key at isvalid.dev. The free tier includes 100 calls per day — enough for most development and low-volume production use.
Full parameter reference and response schema: NPI Validation API docs →
6. Node.js code example
Using the IsValid SDK or the native fetch API. Pass lookup: true to enrich the response with NPPES registry data.
import { createClient } from '@isvalid-dev/sdk'; const iv = createClient({ apiKey: process.env.ISVALID_API_KEY }); // ── Basic validation (checksum only) ──────────────────────────────────────── const basic = await iv.us.npi('1003000126'); if (!basic.valid) { console.log('Invalid NPI'); } else { console.log(`Valid NPI: ${basic.npi}`); console.log(`Check digit: ${basic.checkDigit}`); } // ── With NPPES lookup ─────────────────────────────────────────────────────── const enriched = await iv.us.npi('1003000126', { lookup: true }); if (enriched.valid && enriched.found) { console.log(`Provider: ${enriched.name}`); console.log(`Type: ${enriched.type}`); console.log(`Credential: ${enriched.credential}`); console.log(`Taxonomy: ${enriched.taxonomy.description}`); console.log(`Status: ${enriched.status}`); console.log(`Phone: ${enriched.phone}`); }
In a provider credentialing flow, you might use it like this:
// routes/provider.js (Express) app.post('/provider/verify', async (req, res) => { const { npi, ...rest } = req.body; let npiCheck; try { npiCheck = await validateNpi(npi, { lookup: true }); } catch { return res.status(502).json({ error: 'NPI validation service unavailable' }); } if (!npiCheck.valid) { return res.status(400).json({ error: 'Invalid NPI — check digit failed' }); } if (!npiCheck.found) { return res.status(400).json({ error: 'NPI not found in NPPES registry' }); } if (npiCheck.status !== 'A') { return res.status(400).json({ error: 'NPI is deactivated in the NPPES registry' }); } // Log provider details for credentialing console.log(`Verified: ${npiCheck.name} (${npiCheck.credential})`); console.log(`Taxonomy: ${npiCheck.taxonomy.code} — ${npiCheck.taxonomy.description}`); await enrollProvider({ npi, name: npiCheck.name, ...rest }); res.json({ success: true, provider: npiCheck.name, taxonomy: npiCheck.taxonomy }); });
lookup: true during provider enrollment to verify the provider's name, specialty, and active status. For high-volume claim validation where you only need checksum verification, omit the lookup parameter for faster response times.7. cURL example
Basic NPI validation from the command line:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/us/npi?value=1003000126"
With NPPES registry lookup:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/us/npi?value=1003000126&lookup=true"
Test with an invalid NPI:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/us/npi?value=0000000000"
8. Understanding the response
Basic validation (checksum only):
{ "valid": true, "npi": "1003000126", "checkDigit": "6" }
With NPPES lookup (lookup=true):
{ "valid": true, "npi": "1003000126", "checkDigit": "6", "found": true, "type": "Individual", "name": "ARDALAN ENKESHAFI", "credential": "M.D.", "status": "A", "taxonomy": { "code": "207RG0100X", "description": "Internal Medicine, Gastroenterology" }, "address": { "line1": "...", "city": "...", "state": "...", "postalCode": "...", "country": "US" }, "phone": "443-602-6207", "dataSource": "nppes" }
Invalid NPI:
{ "valid": false }
| Field | Type | Description |
|---|---|---|
| valid | boolean | Whether the NPI passes the Luhn checksum with 80840 prefix |
| npi | string | The 10-digit NPI as submitted |
| checkDigit | string | The 10th digit used for Luhn checksum validation |
| found | boolean | Whether the NPI was found in the NPPES registry (only with lookup) |
| type | string | "Individual" (Type 1) or "Organization" (Type 2) |
| name | string | Provider's name as registered in the NPPES |
| credential | string | Professional credential (e.g. "M.D.", "D.O.", "N.P.") |
| status | string | "A" for active, "D" for deactivated |
| taxonomy | object | Primary taxonomy with code and description |
| phone | string | Practice phone number from the NPPES registry |
lookup=true to verify against the live NPPES registry and check the status field for active enrollment.9. Edge cases to handle
Individual vs. organizational NPIs
NPIs are categorized as Type 1 (individual providers) or Type 2 (organizational providers). A physician working at a hospital has their own Type 1 NPI, while the hospital has a Type 2 NPI. Claims often require both: the rendering provider's individual NPI and the facility's organizational NPI.
// Verify NPI type matches expected usage const result = await validateNpi(npi, { lookup: true }); if (result.found && result.type !== expectedType) { console.warn(`Expected ${expectedType} NPI but got ${result.type}`); // A Type 2 (org) NPI in the rendering provider field is a common claim error }
Deactivated NPIs
An NPI can be deactivated if the provider retires, loses their license, or requests deactivation. A deactivated NPI still passes the Luhn checksum but will appear with status: "D" in the NPPES lookup. Claims submitted with a deactivated NPI will be rejected by payers. Always check the status field when using the lookup feature.
Subpart NPIs (organizations)
Large healthcare organizations can obtain additional "subpart" NPIs for departments, divisions, or service locations. For example, a hospital might have a primary organizational NPI and separate subpart NPIs for its radiology department, laboratory, and pharmacy. Each subpart NPI is independently valid and registered in the NPPES.
NPI reactivation and changes
A deactivated NPI can be reactivated by the original provider. NPIs are never reassigned to a different provider — each NPI is permanently linked to the entity it was originally assigned to. However, providers can update their name, address, taxonomy, and other details in the NPPES registry at any time.
Summary
See also
Validate NPI numbers instantly
Free tier includes 100 API calls per day. No credit card required. Luhn checksum validation, optional NPPES registry lookup, and provider detail extraction in a single call.