Bandeiras de cartão de teste: por que Luhn não é igual para Visa, Mastercard e Amex
Uma validação de cartão costuma nascer testada só com Visa e Mastercard, passa despercebida em code review porque os dois têm 16 dígitos e CVV de 3 números, e quebra na primeira vez que um cliente digita um American Express — 15 dígitos, CVV de 4 números, e um checksum que aparentemente "não bate" porque a lógica foi escrita assumindo um formato que não é universal. O Algoritmo de Luhn é o mesmo para todas as bandeiras, mas o número ao redor dele não é, e é exatamente nessa diferença que a maioria das validações hardcoded quebra.
A anatomia de um número de cartão
Por trás da sequência de dígitos existe uma estrutura definida pelo padrão ISO/IEC 7812, dividida em três partes:
- IIN/BIN (Issuer Identification Number): os primeiros 6 a 8 dígitos, que identificam a bandeira e o banco emissor. É esse prefixo que faz um gateway reconhecer "isso é um Visa" ou "isso é um Amex" antes mesmo de validar o resto do número.
- Número de conta: os dígitos do meio, que identificam o titular dentro da faixa daquele emissor.
- Dígito verificador: o último dígito, calculado sobre todos os anteriores pelo Algoritmo de Luhn — o mesmo checksum usado em CPF/CNPJ, só que com pesos fixos de 2 e 1 alternados em vez de pesos decrescentes.
O que muda de bandeira para bandeira é o tamanho de cada uma dessas partes e a faixa de valores que o IIN pode assumir — e é aí que mora a maior parte dos bugs de validação.
Prefixo e comprimento: a tabela que toda validação deveria consultar
| Bandeira | Prefixo (IIN) | Dígitos | CVV |
|---|---|---|---|
| Visa | 4 | 13, 16 ou 19 | 3 (verso) |
| Mastercard | 51–55 e 2221–2720 | 16 | 3 (verso) |
| American Express | 34 ou 37 | 15 | 4 (frente) |
| Diners Club | 300–305, 36, 38 | 14 | 3 (verso) |
| Discover | 6011, 65 | 16 | 3 (verso) |
| Elo | várias faixas próprias | 16 | 3 (verso) |
A faixa 2221–2720 da Mastercard é a armadilha mais comum em código legado: a bandeira esgotou a faixa histórica 51–55 e passou a emitir cartões também nessa nova faixa a partir de 2017. Uma regex ou validação escrita antes disso — e nunca revisitada — rejeita como "bandeira não reconhecida" um Mastercard real e atual, um bug silencioso porque o número em si é perfeitamente válido, só não bate com um prefixo desatualizado na lógica.
Por que o comprimento ímpar da Amex confunde implementações de Luhn
O Algoritmo de Luhn processa os dígitos da direita para a esquerda, dobrando o valor de cada dígito em posição par a partir do segundo (contando do fim) e somando os dígitos do resultado quando ultrapassa 9. Em um número de 16 dígitos (par), os dígitos que recebem o dobro sempre caem nas posições ímpares quando contados da esquerda — e é comum uma implementação fixar essa observação como regra ("dobra os dígitos de índice par contado da esquerda") em vez de implementar a regra real, que conta a partir da direita. Com 16 dígitos as duas abordagens coincidem, escondendo o erro. Com os 15 dígitos da Amex (ímpar), elas divergem: a implementação "fixada" dobra os dígitos errados, o checksum dá errado para todo Amex, e o sintoma parece ser "número inválido" quando na verdade é a lógica de Luhn que está sutilmente errada — e só a bandeira de comprimento ímpar expõe isso.
CVV não é sempre 3 dígitos nem sempre fica atrás
Outra suposição comum que quebra com Amex: o campo de código de segurança tem maxlength="3" fixo no formulário, e a mensagem de ajuda diz "os 3 números no verso do cartão". A American Express usa 4 dígitos, chamados de CID (Card Identification Number), impressos na frente do cartão, acima do número — não atrás. Um checkout que trava em 3 dígitos ou que só explica "verso do cartão" não impede o pagamento de um jeito grave, mas gera confusão e abandono de carrinho no exato momento em que o cliente já decidiu comprar.
Casos de teste que valem mais que "gerar um número qualquer"
- Um número válido de cada bandeira suportada, com o comprimento correto — não apenas Visa/Mastercard de 16 dígitos.
- Um Mastercard com prefixo na faixa nova (
2221–2720), para garantir que o reconhecimento de bandeira não está preso à faixa antiga. - Um Amex completo, verificando que o formulário aceita 15 dígitos e exige 4 no campo de segurança, com o rótulo correto ("código de 4 dígitos na frente do cartão").
- Um número com o comprimento certo para a bandeira, mas dígito verificador alterado em uma posição — deve falhar no Luhn independentemente do comprimento.
- Um número com prefixo de bandeira não suportada pelo checkout (ex.: Diners, se a loja não aceita) — deve ser rejeitado com mensagem clara, não com erro genérico de formato.
O Gerador de Cartão deste site já gera números Luhn-válidos com o prefixo e o comprimento corretos de Visa, Mastercard, Amex e Discover, prontos para alimentar esse tipo de caso de teste sem montar o número na mão. Para o outro lado da validação — o que acontece depois que o formulário aceita o número — vale complementar com a leitura de Cartão de teste em gateway de pagamento: por que um número Luhn-válido não basta, que cobre os cartões oficiais de sandbox usados para testar aprovação, recusa e 3DS.