Home

/

Keep PII Out of Your LLM

/

NPI, in C#

NPI, in C#

Chapter 5
Part II
4
min read

NPI, in C#

The National Provider Identifier, issued by CMS to US healthcare providers. Ten digits, and the check digit is a standard Luhn, computed after prepending the fixed prefix 80840. That prefix is the part implementations miss, and without it every valid NPI fails.

public static bool IsNpiValid(string npi)
{
    var digits = new string(npi.Where(char.IsDigit).ToArray());
    if (digits.Length != 10) return false;

    // CMS specifies Luhn over the NPI prefixed with 80840.
    return IsLuhnValid("80840" + digits);
}

Known-valid test values: 1993999998, 1234567893.

Appendix A carries the rest: Social Security numbers, EINs, ITINs, Medicare Beneficiary Identifiers, IBANs for international customers, and the false-positive characteristics of each.

What this layer cannot do

Look back at the Chapter 4 table, at the CoNLL-2002 column. Regex scored 0.000. Not low. Zero.

That dataset is newspaper text annotated for person names and locations. There is no pattern for a name. There is no checksum for "Springfield". The entire category of unstructured personal data, which is most personal data, is invisible to this layer.

So the honest summary of deterministic detection is a narrow instrument with excellent precision:

EntityDeterministic?Confidence
Payment cardYes, LuhnVery high
ABA routing numberYes, weighted mod-10Very high
NPIYes, Luhn with 80840 prefixVery high
IBANYes, mod-97Very high
SSN, EIN, ITINRange rules onlyMedium, needs context
Email addressYes, RFC patternHigh
IP addressYesHigh, but often not personal data in context
Phone numberPartlyMedium, format varies wildly
ZIP codePartlyMedium, collides with other codes
Person nameNoNone
AddressNoNone
Free-text disclosureNoNone

The bottom three rows are why Chapter 6 exists.

The gap is structural rather than a matter of effort. A checksum works because someone designed the identifier to be machine-verifiable. Nobody designed names. There is no length a name must be, no character set it must use, no rule distinguishing "Brook" the person from "brook" the watercourse, and no way to tell that "Mercedes" is a colleague rather than a car without reading the sentence. The same applies to addresses, to dates that are sometimes dates of birth, and to the sentence where a customer volunteers a medical condition.

That is the boundary. Everything with a designed structure belongs to this layer and belongs to it completely. Everything a human wrote in their own words belongs to a model, with the accuracy that Chapter 4 established, which is worse than you would like and better than nothing.

Two practical warnings

Do not tune these for recall. The value of this layer is that when it fires, it is right. If you loosen the card pattern to catch cards written with unusual separators, you start matching order references, and every false positive damages a downstream result while adding nothing you can rely on. Let this layer be precise and let the model layer chase recall.

Validators drift. Identifier schemes change. Countries add digits, reassign ranges, introduce new formats. A validator written in 2021 against a scheme revised in 2025 fails silently, returning false for legitimate identifiers, which reads as "no PII found". Put a dated comment on every validator naming the scheme version, and add a golden test with known-valid examples, so a scheme change fails a test rather than failing open in production.

That second warning generalises into a principle for the whole book: a detection component that fails should fail loudly, because a detector that returns nothing looks exactly like clean input.

You now have a fast, precise layer that finds structured identifiers and is blind to names, addresses, and everything a person typed in their own words. That is the majority of the problem, and closing it means a model. There are three ways to get one into a .NET application, and they differ in the one dimension this book cares about most.

Sources for this chapter

  • ABA routing number check digit, weights 3-7-1 mod 10 — Apache Commons Validator reference implementation: https://commons.apache.org/validator/apidocs/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigit.html · algorithm walkthrough: http://www.brainjar.com/js/validation/
  • NPI check digit: Luhn over 80840 + NPI — CMS, Requirements for National Provider Identifier (NPI) and NPI Check Digit: https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf · worked example: https://www.johndcook.com/blog/2024/06/26/npi-number/
  • Luhn — ISO/IEC 7812-1. IBAN mod-97 — ISO 13616.
  • Latency figures and the 0.171 regex average F1 — Sikkema benchmark, cited in full in Chapter 4.

Every validator in this chapter and in Appendix A was executed against the stated known-valid test values before publication. The argument that this layer's value is precision rather than recall is the author's, supported by the 0.000 regex score on CoNLL-2002 in the Chapter 4 table.

the-leak-you-cant-see
blast-radius
what-counts-as-pii
the-five-doors
the-accuracy-reckoning
the-hybrid-that-does-not-work
deterministic-detection
npi-in-c
the-three-way-choice
calling-the-analyzer-from-c
measuring-your-own-demo-gap
choosing-the-operating-point
the-ladder-of-safeguards
pseudonymisation
the-round-trip
restoring-safely
when-masking-breaks-the-task
plausibility-hazard
the-architecture-that-holds
the-reference-architecture
dont-send-it-at-all
structure-beats-prose
the-gateway
failure-is-a-policy-decision
the-sidecar-you-can-trust
egress-deny-it-at-the-network
rag-and-agents
de-identify-before-you-embed
dual-model-separation
the-boring-controls
evidence-and-the-first-thirty-days
week-two-the-chokepoint-and-the-fast-layer
entity-catalogue-and-c-validators
mbi-positional-rules
tooling-at-a-glance
azure-ai-language-pii-in-detail
container-trust-checklist
sources
azure-ai-language
provider-retention

Download the full PDF for free?

Free download — no account required

Get the PDF
Get the PDF
Related Chapters
Free Download
Get the full PDF
All pages, including all code examples, diagrams, and the appendix reference card.
No spam. Unsubscribe at any time.
Your email won't be shared.
Oops! There's a problem with your request. We're working on fixing it. Please try again later.