Guide · Python · SDK · REST API

NPI Validation in Python — 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.

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.

1003000126
1003000 = provider number12 = sequence6 = check digit

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.

Digits808401003000126
Double?noyesnoyesnoyesnoyesnoyesnoyesnoyesno

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 Python:

# npi_check_digit.py — NPI Luhn validation with 80840 prefix
import re


def is_valid_npi(npi: str) -> bool:
    """Validate an NPI using the Luhn algorithm with the 80840 prefix."""
    if not re.fullmatch(r"\d{10}", npi):
        return False

    # Prepend the 80840 prefix to form a 15-digit number
    full = "80840" + npi
    digits = [int(c) for c in full]

    total = 0
    double = False

    # Process from right to left (standard Luhn)
    for i in range(len(digits) - 1, -1, -1):
        d = digits[i]
        if double:
            d *= 2
            if d > 9:
                d -= 9
        total += d
        double = not double

    return total % 10 == 0


print(is_valid_npi("1003000126"))  # True
print(is_valid_npi("1003000127"))  # False — bad check digit
ℹ️The Luhn algorithm with the 80840 prefix catches all single-digit transcription errors and most adjacent transpositions. However, it does not verify that the NPI is actually assigned to a provider in the NPPES registry.

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.

Luhn
Checksum
80840 prefix validation
Optional
NPPES lookup
live registry query
100/day
Free tier
no credit card

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. Python code example

Using the isvalid-sdk Python SDK or the requests library. Install with pip install isvalid-sdk or pip install requests. Pass lookup=True to enrich the response with NPPES registry data.

# npi_validator.py
import os
from isvalid_sdk import IsValidConfig, create_client

iv = create_client(IsValidConfig(api_key=os.environ["ISVALID_API_KEY"]))

# ── Basic validation (checksum only) ────────────────────────────────────────

basic = iv.us.npi("1003000126")

if not basic["valid"]:
    print("Invalid NPI")
else:
    print(f"Valid NPI: {basic['npi']}")
    print(f"Check digit: {basic['checkDigit']}")

# ── With NPPES lookup ───────────────────────────────────────────────────────

enriched = iv.us.npi("1003000126", lookup=True)

if enriched["valid"] and enriched.get("found"):
    print(f"Provider: {enriched['name']}")
    print(f"Type: {enriched['type']}")
    print(f"Credential: {enriched['credential']}")
    print(f"Taxonomy: {enriched['taxonomy']['description']}")
    print(f"Status: {enriched['status']}")
    print(f"Phone: {enriched['phone']}")

In a provider credentialing flow, you might use it like this with Flask:

# app.py (Flask)
from flask import Flask, request, jsonify

app = Flask(__name__)


@app.post("/provider/verify")
def verify_provider():
    data = request.get_json()

    try:
        npi_check = validate_npi(data["npi"], lookup=True)
    except requests.RequestException:
        return jsonify(error="NPI validation service unavailable"), 502

    if not npi_check["valid"]:
        return jsonify(error="Invalid NPI — check digit failed"), 400

    if not npi_check.get("found"):
        return jsonify(error="NPI not found in NPPES registry"), 400

    if npi_check["status"] != "A":
        return jsonify(error="NPI is deactivated in the NPPES registry"), 400

    # Log provider details for credentialing
    name = npi_check["name"]
    taxonomy = npi_check["taxonomy"]
    app.logger.info(f"Verified: {name} ({npi_check['credential']})")
    app.logger.info(f"Taxonomy: {taxonomy['code']} — {taxonomy['description']}")

    enroll_provider(npi=data["npi"], name=name)
    return jsonify(success=True, provider=name, taxonomy=taxonomy)
Use 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
}
FieldTypeDescription
validbooleanWhether the NPI passes the Luhn checksum with 80840 prefix
npistringThe 10-digit NPI as submitted
checkDigitstringThe 10th digit used for Luhn checksum validation
foundbooleanWhether the NPI was found in the NPPES registry (only with lookup)
typestring"Individual" (Type 1) or "Organization" (Type 2)
namestringProvider's name as registered in the NPPES
credentialstringProfessional credential (e.g. "M.D.", "D.O.", "N.P.")
statusstring"A" for active, "D" for deactivated
taxonomyobjectPrimary taxonomy with code and description
phonestringPractice phone number from the NPPES registry
⚠️A valid NPI checksum confirms that the number is structurally correct. It does not guarantee the NPI is currently active or assigned. Use 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
result = validate_npi(npi, lookup=True)

if result.get("found") and result["type"] != expected_type:
    print(f"Expected {expected_type} 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

Do not rely on Luhn checksum alone — it does not verify NPPES enrollment
Do not ignore the NPI type — individual and organizational NPIs serve different purposes
Validate the Luhn checksum with the 80840 prefix for structural integrity
Use lookup=True to verify against the live NPPES registry
Check the status field to catch deactivated NPIs before claim submission
Verify the taxonomy code matches the expected specialty for credentialing

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.