Every credit card number has a built-in checksum digit, and the algorithm that checks it (Luhn's algorithm) predates modern computing — it was patented in 1954, before credit cards as we know them existed.
function luhnValid(number) {
const digits = number.replace(/\D/g, "").split("").reverse().map(Number);
const sum = digits.reduce((acc, digit, i) => {
if (i % 2 === 1) {
digit *= 2;
if (digit > 9) digit -= 9;
}
return acc + digit;
}, 0);
return sum % 10 === 0;
}
This only checks that the number is structurally valid — it says nothing about whether the card exists, is active, or has funds. That's a completely separate (and much more sensitive) concern that needs a real payment processor, not a format checker.
Brand detection (Visa vs Mastercard vs Amex) is a second, separate step based on the IIN/BIN prefix ranges. I bundled both into one endpoint on Validate since they're almost always needed together. Same account also runs QR API and Currency API.
Top comments (0)