Quando você digita um número de cartão errado em um checkout bem-feito, a mensagem de erro aparece antes mesmo de o formulário ser enviado. Não há consulta ao banco, não há chamada ao adquirente — há uma conta de somar que existe desde os anos 1950 e continua fazendo o mesmo trabalho: detectar dígito digitado errado.
O algoritmo de Luhn é simples o bastante para ser feito de cabeça e é o motivo de a maioria dos erros de digitação de cartão nunca chegar ao processador de pagamento. Vale entender o que exatamente ele garante — e o que muita gente acha que ele garante e não é verdade.
Como o cálculo funciona
O procedimento tem quatro passos, aplicados sobre os dígitos do número da direita para a esquerda.
- 1Percorra os dígitos da direita para a esquerda, começando pelo último.
- 2Dobre o valor de cada dígito em posição par nessa contagem — ou seja, o segundo, o quarto, o sexto, e assim por diante.
- 3Se o resultado da duplicação passar de 9, subtraia 9. Isso equivale a somar os dois algarismos do produto.
- 4Some todos os valores. O número é válido pelo Luhn se a soma for múltiplo de 10.
Acompanhe com o número de teste 4539 1488 0343 6467, um dos exemplos mais citados em documentação de pagamento.
| Posição (da direita) | Dígito | Dobra? | Valor somado |
|---|---|---|---|
| 1 | 7 | Não | 7 |
| 2 | 6 | Sim → 12 → 12-9 | 3 |
| 3 | 4 | Não | 4 |
| 4 | 6 | Sim → 12 → 12-9 | 3 |
| 5 | 3 | Não | 3 |
| 6 | 4 | Sim → 8 | 8 |
| 7 | 3 | Não | 3 |
| 8 | 0 | Sim → 0 | 0 |
Continuando pelos oito dígitos restantes e somando tudo, chega-se a 80 — múltiplo de 10, portanto o número passa no Luhn.
export function validarLuhn(entrada) {
const digitos = String(entrada).replace(/\D/g, "");
if (digitos.length < 12) return false;
let soma = 0;
let dobrar = false;
// Da direita para a esquerda.
for (let i = digitos.length - 1; i >= 0; i--) {
let valor = digitos.charCodeAt(i) - 48;
if (dobrar) {
valor *= 2;
if (valor > 9) valor -= 9;
}
soma += valor;
dobrar = !dobrar;
}
return soma % 10 === 0;
}O que o Luhn detecta e o que escapa
O algoritmo foi projetado para um problema específico: alguém digitando manualmente uma sequência longa de números. Ele acerta em cheio nesse cenário e é indiferente a outros.
| Tipo de erro | Exemplo | Detectado? |
|---|---|---|
| Um dígito trocado | 4539 → 4549 | Sempre |
| Transposição de adjacentes | 45 → 54 | Quase sempre |
| Transposição de 09 ou 90 | 09 → 90 | Nunca |
| Dois dígitos trocados de uma vez | 4539 → 4629 | Às vezes |
| Dígito faltando ou sobrando | 16 → 15 dígitos | Quase sempre, pelo tamanho |
A linha do 09 e 90 é a limitação conhecida do algoritmo. Ela existe porque dobrar 0 dá 0 e dobrar 9 dá 18, que vira 9 depois da subtração — a troca não altera a soma. Nenhuma implementação corrige isso, porque a correção exigiria um algoritmo diferente.
O que o Luhn não é
Aqui mora a confusão que aparece em revisão de código e em conversa com produto.
- Não é autenticação: não diz nada sobre quem digitou o número.
- Não é verificação de existência: a esmagadora maioria dos números que passam no Luhn nunca foi emitida por ninguém.
- Não é antifraude: um fraudador com um número real e válido passa no Luhn tão bem quanto um cliente legítimo.
- Não é criptografia: não há segredo envolvido, e qualquer um calcula o dígito final de um número incompleto.
O único papel do Luhn é economizar uma ida ao adquirente quando o usuário errou uma tecla, e transformar a recusa genérica em uma mensagem útil no campo certo do formulário.
O que vem antes e depois do Luhn no checkout
Um formulário de pagamento bem construído aplica várias verificações em camadas, cada uma respondendo a uma pergunta diferente.
| Camada | Pergunta | Onde acontece |
|---|---|---|
| Tamanho e caracteres | O campo tem o formato esperado? | Cliente |
| Faixa do BIN | Qual bandeira e que máscara aplicar? | Cliente |
| Luhn | Há erro de digitação? | Cliente |
| Autorização | O cartão existe, está ativo e tem limite? | Adquirente e emissor |
| Antifraude | A transação é legítima? | Motor de risco |
| Autenticação 3-D Secure | O portador aprovou? | Emissor |
Números de teste e por que eles existem
Para testar máscara, detecção de bandeira, mensagens de erro e layout do formulário, é preciso de números que passem no Luhn. Usar um cartão real para isso é desnecessário e arriscado — inclusive porque o número acaba em captura de tela, em fixture versionada e em log de desenvolvimento.
O gerador de cartão do Codigio Labs monta números que satisfazem o Luhn a partir do prefixo da bandeira escolhida, inteiramente no navegador. Eles servem para exercitar a interface e a validação local, e não correspondem a nenhuma conta existente.
Resumo
- O Luhn soma os dígitos dobrando um a cada dois da direita para a esquerda e exige que o total seja múltiplo de 10.
- Detecta todo erro de um dígito e quase toda transposição adjacente, exceto 09 contra 90.
- Passar no Luhn não indica existência, titularidade, saldo nem legitimidade.
- Valide no cliente para dar feedback imediato e nunca armazene o número completo.
- Para testar cobrança de verdade, use os cartões de teste do seu provedor.