Technical fundamentals
Luhn Algorithm: What It Is and How It Works to Validate Credit Cards
Published: · 10 min read
The Luhn algorithm is a checksum formula that lets you verify whether a credit card number is correctly written: it is applied to the 16 digits, performs a sum with selective doublings and checks whether the total is divisible by 10.
Key points
- The Luhn algorithm (or "modulo 10") is a checksum, not a verification that the card exists.
- It was created by Hans Peter Luhn at IBM, in 1954, and today it is a de facto standard for cards, IMEI numbers and EAN/UPC codes.
- It works in 5 steps: reverse, double alternating positions, sum digits, add everything up and check modulo 10.
- You can calculate the check digit (the last one) so that any prefix becomes valid.
- It is implemented in just a few lines of JavaScript, Python or PHP, with no external dependencies.
If the result is a multiple of 10, the number is "valid" according to Luhn; if not, there is a typing error. That is all it does: it detects errors, it does not confirm that a card exists. A number can pass Luhn and not belong to any real account. That is why it is the basis of test card generators and of most of the validators used by developers.
In this guide you will understand what the Luhn algorithm is, how it works step by step, how the check digit is calculated and how to implement it in JavaScript, Python and PHP. You will also see what it detects and what it does not, and why it is so useful when you test payment software.
What the Luhn algorithm is and where it comes from
The Luhn algorithm, also called the Luhn formula or modulo 10, is a simple method for validating identification numbers. Its goal is to detect two very common types of errors when typing by hand:
- A mistyped digit (for example, typing 4 instead of 5).
- A swap of two adjacent digits (for example, typing 67 instead of 76).
It was designed by Hans Peter Luhn, a German engineer who worked at IBM and went on to register more than 80 patents. He presented the method in 1954, and the company first popularised it to validate credit card numbers. Over time, bodies such as ISO adopted it, and today it appears in virtually every system that needs to check a long number without querying a database.
The great advantage of Luhn is that it needs neither the internet nor a list of cards. It is pure mathematical computation: it runs in microseconds, in any language and on any device. That is why payment gateways use it as a first filter before doing a real check against the issuer.
Luhn is not exclusive to cards
Although we associate it with credit cards, the algorithm applies to many numeric identifiers:
- IMEI of mobile phones (15 digits).
- EAN-13, UPC-A and other product barcodes.
- Account numbers in some banking systems.
- Social Security numbers in certain countries and other official documents.
That detail matters: if you see that an IMEI passes Luhn, it does not mean the phone exists; only that the number is well formed.
How the Luhn algorithm works step by step
The Luhn algorithm works on the digits from right to left. These are the 5 steps:
- Write down the number and count from the right. The last digit (the one on the right) is the check digit.
- Double every other digit. Starting from the second digit from the right, double the value of each digit in an alternating position.
- Reduce two-digit results. If doubling gives you a two-digit number (for example, 8 × 2 = 16), add its digits together (1 + 6 = 7). This is equivalent to subtracting 9 from the result.
- Add all the digits. Include both the ones you doubled and the ones you did not.
- Check modulo 10. If the total sum is divisible by 10, the number is valid according to Luhn.
One detail that confuses many people: the check digit is not doubled. Only the alternating positions starting from the second digit counted from the right are doubled.
A practical example with the number 4539 1488 0343 6467
Let us validate a classic test number, 4539 1488 0343 6467, which starts with 4 (the Visa prefix). We lay out the digits and apply the steps:
| Digit | 4 | 5 | 3 | 9 | 1 | 4 | 8 | 8 | 0 | 3 | 4 | 3 | 6 | 4 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Double? | Yes | No | Yes | No | Yes | No | Yes | No | Yes | No | Yes | No | Yes | No | Yes | No |
| Value after the step | 8 | 5 | 6 | 9 | 2 | 4 | 7 | 8 | 0 | 3 | 8 | 3 | 3 | 4 | 3 | 7 |
Now we add up all the values in the last row:
8 + 5 + 6 + 9 + 2 + 4 + 7 + 8 + 0 + 3 + 8 + 3 + 3 + 4 + 3 + 7 = 80
Since 80 is divisible by 10, the number 4539 1488 0343 6467 is valid according to the Luhn algorithm. If you had mistyped a single digit, the sum would not have been a multiple of 10 and the algorithm would have caught it.
Want to check it yourself without doing the math? Paste any number into our credit card validator and it will instantly tell you whether it passes Luhn, as well as detecting its type and its BIN.
How to generate the check digit (checksum)
Validating is useful, but sometimes you need the opposite: start from a prefix and calculate the last digit so that the full number is valid. This is exactly what a test card generator does.
The procedure is the reverse of validation:
- Take the number without the last digit (the prefix you already have).
- Apply steps 2 and 3 of the Luhn algorithm (double alternating positions from the right) to those digits.
- Add all the values.
- Calculate the remainder of that sum modulo 10.
- The check digit is (10 − remainder) modulo 10.
If the remainder is 0, the check digit is 0. In any other case, it is the difference up to the next multiple of 10.
For example, if after adding up you get a total of 76, the remainder modulo 10 is 6 and the check digit will be 10 − 6 = 4. With that 4 at the end, the total sum would be 80, divisible by 10.
This trick is the heart of tools such as our credit card generator: it combines a real BIN, generates random digits and calculates the checksum so that every number passes Luhn.
How to implement the Luhn algorithm in code
The best part of the algorithm is how short it is. Here are three implementations ready to copy into your tests.
JavaScript
function isLuhnValid(number) {
// Strip spaces and hyphens, then work from right to left
const digits = number.replace(/\D/g, '').split('').reverse().map(Number);
let sum = 0;
digits.forEach((digit, i) => {
let value = digit;
if (i % 2 === 1) { // alternating positions (starting with the second)
value *= 2;
if (value > 9) value -= 9; // equivalent to adding the two digits
}
sum += value;
});
return sum % 10 === 0;
}
console.log(isLuhnValid('4539148803436467')); // true
console.log(isLuhnValid('4539148803436468')); // false
Python
def luhn_valid(number: str) -> bool:
digits = [int(d) for d in str(number) if d.isdigit()][::-1]
total = 0
for i, digit in enumerate(digits):
value = digit
if i % 2 == 1:
value *= 2
if value > 9:
value -= 9
total += value
return total % 10 == 0
print(luhn_valid("4539148803436467")) # True
print(luhn_valid("4539148803436468")) # False
PHP
function isLuhnValid(string $number): bool {
$digits = array_reverse(str_split(preg_replace('/\D/', '', $number)));
$sum = 0;
foreach ($digits as $i => $digit) {
$value = (int) $digit;
if ($i % 2 === 1) {
$value *= 2;
if ($value > 9) {
$value -= 9;
}
}
$sum += $value;
}
return $sum % 10 === 0;
}
var_dump(isLuhnValid('4539148803436467')); // bool(true)
var_dump(isLuhnValid('4539148803436468')); // bool(false)
In all three cases the pattern is the same: reverse the digits, double the odd positions, reduce two-digit numbers and check modulo 10. You can port it to Java, C#, Go or any other language in minutes.
What the Luhn algorithm detects and what it does not
Here is the most common misunderstanding, and it is worth making clear once and for all.
What it does detect:
- A mistyped digit (a simple typing error).
- A swap of two adjacent digits, in most cases.
- Incomplete numbers or numbers with an extra digit.
What it does not detect:
- It does not confirm that the card exists. An invented number can pass Luhn perfectly well.
- It does not verify that there are funds or that the card is active.
- It does not validate the CVV, the expiration date or the cardholder.
- It does not guarantee that the BIN is real or that it corresponds to a legitimate issuer.
- It does not detect certain digit swaps or double errors that cancel each other out.
Put another way: Luhn tells you whether a number is well formed, not whether it is real. It is a data quality filter, not a payment authorisation.
That is why, when a validator tells you "valid number", it is really telling you "valid according to Luhn". Checking whether the card is genuine can only be done by the payment gateway against the issuer, and that is part of another phase of the process.
A real QA case
Marta worked as a QA at a fintech and had an intermittent bug: the checkout form rejected certain test cards. After two days reviewing the backend, she discovered that the problem was in a frontend validation that required exactly 16 digits. American Express cards have 15, so the validation discarded them before they reached the server. Relaxing the length and adding a Luhn check was enough for each network to accept its correct format. The bug was not in the algorithm, but in assuming that all cards are the same.
Other uses of the Luhn algorithm: IMEI, EAN and UPC
The Luhn algorithm is not limited to cards. Here are some contexts where you will find it:
- Mobile IMEI numbers. The 15 digits of an IMEI end in a check digit calculated with Luhn. This is what makes it possible to validate an IMEI without querying any database.
- EAN-13 and EAN-8 codes. Product barcodes use a checksum compatible with the same logic.
- UPC-A. The 12-digit North American barcode also applies a final check digit.
- Identification numbers of some countries and security documents that need a quick verification.
It is no coincidence that an identifier uses Luhn: it is the cheapest way to detect transcription errors in any long number. If you are going to design your own numbering system (coupons, licences, order codes), Luhn is an excellent option for adding a check digit without overcomplicating things.
Test cards and Luhn go hand in hand
When you develop payment software, you need numbers that pass the client-side validation but cannot be used to buy anything. That is where Luhn becomes your ally: you can generate endless valid numbers without risking real data. If you want specific examples by network, take a look at our Visa card generator or check the directory of test cards and our guide to Stripe and PayPal test cards for official scenarios.
Ready to test with Luhn-valid numbers? Open the credit card generator, choose the network and export up to 9999 numbers in JSON, CSV or XML in seconds.
Conclusion
The Luhn algorithm is one of those small pieces that hold up enormous systems. With five steps and one modulo 10 operation, it detects most typing errors in any long number, with no databases and no connection.
The important thing to remember is its real scope: it validates the format, not the authenticity. That nuance is key when you test payment software, because it lets you use invented, Luhn-valid numbers without ever touching real data.
If you work in QA or development, always keep two tools at hand: a validator to check numbers and a generator to create test batches. With both, any payment integration can be tested faster and without risk.
Responsible use notice: the numbers generated on this site are fictitious and valid only under the Luhn algorithm. They do not correspond to real cards, cannot be used to make purchases and must be used only for software testing. Using them for fraud or impersonation is illegal.
Sources and further reading
- Wikipedia, "Luhn algorithm": en.wikipedia.org/wiki/Luhn_algorithm
- Wikipedia, "Hans Peter Luhn": en.wikipedia.org/wiki/Hans_Peter_Luhn
- What a card's BIN is and what its first digits reveal
- What a card's CVV or CVC is and what it is for
Frequently Asked Questions
Does the Luhn algorithm confirm that a card is real?
No. It only checks that the number is well formed. A real card and an invented number can both pass Luhn equally.
Why is it called "modulo 10"?
Because the final criterion is that the total sum be divisible by 10, that is, that its remainder modulo 10 be zero.
Does Luhn work with all cards?
Yes, the main networks (Visa, Mastercard, American Express, Discover, JCB and Diners Club) use the Luhn check digit, even though their length and prefix differ.
Can I use Luhn to validate an IMEI?
Yes. The last digit of an IMEI is a Luhn checksum, so the same code works to validate it.
Luhnmodulo 10validationchecksum
Ready to generate your test numbers?
Use the free generator and get Luhn-valid cards with CVV and expiry in seconds.