NPI Luhn Check Digit Calculation

Posted by on November 15, 2011 in Health Care, Javascript, Programming | 20 comments

If you need to make up a fake NPI, you can’t just throw any 10 digits together and have it wind up as a valid NPI.
NPI for those who don’t know is National Provider Identifier. You probably know that if you’re looking for a way to generate them though.
The first digit has to be one or two and the last digit is actually a check digit of the rest of the digits plus a prefix that’s applied to the NPI to make a different identification number. CMS has a big article about it: Requirements for National Provider Identifier (NPI) and NPI Check Digit

Here’s the summary:

  1. Create a random 9 digit number starting with 1 or 2.
  2. Double the value of alternate digits, beginning with the rightmost digit.
  3. Add the prefix 80840 to the left.  Do not double these digits.
  4. Add up all the individual digits. (if you doubled 9 and got 18, add 1+8=9, not 18. double 7 and get 1+4=5 not 14)
  5. Your check digit is now the difference between your sum of all the digits and the next rounded 10.  IE if your sum is 62, your check digit is 8.  If it’s 50, your check digit is 0.
Below is a calculator I wrote to generate the check digit of a random 9 digit start. Type your random 9, then click outside the box.

The code for the generation is below.

var newNPI = ”;
var base = this.value;
var count = 0;
var newCount = 0;
for(i=base.length-1; i>=0; i–)
if(count % 2 == 0)
{var tempNum = base.charAt(i)*2;
if(tempNum >= 10)
{var tempRemainder = tempNum % 10;
newCount = newCount + tempRemainder + 1;
newCount = newCount + tempNum;
newCount = newCount + parseInt(base.charAt(i));
newCount = newCount + 24;
var newMod = newCount % 10;
var checkDigit = (10 – newMod) % 10;
newNPI = base + checkDigit.toString();
If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.


  1. That algorithm has a bug. If you input an NPI as say, 100390647, it returns 10039064710, being the check digit number 10. The check digit should be zero. Nonetheless, thanks for the post and your insights.

    • Thanks for the info. I’ll get a fix in place when I have time.

  2. Andrew, your code runs into the same problem I hit doing a bash implementation. If newCount is divisible by 10, then newMod will be zero, and checkDigit will be 10. When you append checkDigit to base, you end up with an extra digit. To avoid it, you can either add in a molulo 10, or add a check for newMod being 10 and forcing it to zero.

    Nice code, and thanks for sharing!

    • Thanks for the tip. I’ll have to modify things to account for that.

  3. Andrew: Thanks for sharing this! I was about to sit down and write the exact same thing. I appreciate your effort. 🙂

    • You’re welcome Micah

  4. I know this is an old post, but it was one of the first I found today when looking for a solution to my problem.

    My creation solves the odd problem explained above and I’ve tested it several thousand times without fail.

    Get it here:

    • That works too!

    • Hi guys–I don’t suppose any of you know where I can find an equivalent generator in VB/VBA–my job requires me to write in it 🙂 I thought about trying to create it myself, but I’m nervous I’ll get it completely wrong… at some point, I will want to learn Java/JS, I just haven’t gotten to that point yet.

  5. “3. Add the prefix 80840 to the left. Do not double these digits.”

    We have to double every other digit of these numbers as well. Otherwise, the simple case of 123456789 gives the sum of 63, i.e., check digit comes out to be 7. Which is wrong.
    Please correct me if I’m missing something. And thanks for sharing it. @ALEX, thanks to you too!

  6. After all of these years since the NPI’s started, your check digit calculator is still great to have out on the web. Thanks for leaving it here!

  7. Great resource for a project I was working on. Thank you very much for posting this. I ran into the same issue with the check digit of 0. It would calculate as a check digit of 10 and the NPI would be considered invalid.

    If you are interested, I fixed the problem by adding one more calculation.

    I’ve seen this in other places too. This problem is from the algorithm description:
    Step 3: Subtract from next higher number ending in zero. 70 – 67 = 3 Check digit = 3 NPI with check digit = 1234567893
    But it doesn’t really take into account the fact that the “next higher number ending in zero” will actually result in a check digit of 10 when the current number already ends in 0. (ex: Starting at 60, the next higher digit ending in zero would be 70 and 70-60 = 10)

    To fix it, I basically put in one additional calculation. Using pseudo code:
    Original: 10 – (newMod mod 10)
    New: (10 – (newMod mod 10)) mod 10

    I think for the formula posted in this site, the new formula would look like this:
    var checkDigit = (10 – newMod) % 10;

    The extra mod 10 on the whole formula will always result in the original number as long as the original number is less than 10. If the original number=10, then (10 mod 10) = 0 and gives us the correct check digit calculation. Going back to the original example ((70-60) mod 10) = 0

    • I’ve implemented and updated that checkdigit line with your fix. Thank you.

  8. You have a bug – when I enter “999999987” I get “99999998710”. which is too many digits.

    • Well yes, that is correct. But as the input describes, the random number has to start with a 1 or 2. I’ve put some input checks in my javascript, but didn’t include them in the display of it since it’s not important to the logic.

  9. I do have an NPI, which I manually calculated based on your algorithm, but resulting checksum doesn’t match the real checksum…

    • What was the failed NPI?

  10. The calculator appears to no longer be working.

    • Can you be more specific?

  11. This is a very useful tool . Thank you very much. Our entire team uses this tool.

Leave a Comment

Your email address will not be published. Required fields are marked *