Conta corrente em Node.js: calculando o dígito verificador po...
Conta corrente em Node.js: calculando o dígito verificador por banco
Cada banco brasileiro calcula o dígito verificador de conta corrente com um algoritmo próprio. Sem entender essas regras, qualquer gerador de dados de teste vai produzir contas que parecem válidas mas falham na primeira chamada à API do seu banco. Este guia implementa os cinco bancos mais comuns em TypeScript e monta um dispatcher por código COMPE.
O que é o dígito verificador de conta corrente no Brasil
Por que cada banco tem um algoritmo diferente
O Banco Central padroniza o formato de conta via FEBRABAN, mas não impõe o algoritmo do DV. Cada instituição escolhe o método ao definir sua numeração interna. O resultado é uma proliferação de variantes de mod-10 e mod-11 que convivem no mesmo sistema bancário.
Diferença entre dígito da agência e dígito da conta
A agência tem seu próprio DV, calculado separadamente da conta. No Itaú, os dois são concatenados antes do cálculo. No Santander, a agência não tem DV próprio. Confundir os dois é a origem de boa parte dos bugs em integrações bancárias.
Formato padrão FEBRABAN: agência / conta + DV
O padrão de exibição é AAAA-D / CCCCCCC-D, onde AAAA é a agência, D é o dígito verificador da agência, CCCCCCC é a conta e o D final é o DV da conta. A barra separa agência de conta; o hífen separa conta de DV.
---
Fundamentos: módulo 10 e módulo 11 aplicados a contas bancárias
Como funciona o mod-11 (pesos 2-9, base padrão)
Multiplica cada dígito, da direita para a esquerda, por pesos sequenciais que começam em 2 e vão até 9, reiniciando em 2 se necessário. Soma os produtos, calcula o resto da divisão por 11 e subtrai de 11. Se o resultado for 10 ou 11, a regra de tratamento varia por banco.
Como funciona o mod-10 (pesos alternados 2-1)
Multiplica os dígitos alternando pesos 2 e 1, da direita para a esquerda. Se o produto de um dígito for maior que 9, soma os algarismos do resultado (ex: 14 → 1+4 = 5). Soma tudo, calcula o resto por 10 e subtrai de 10. Resto 0 → DV 0.
Tratamento dos restos 0 e 1 — os casos que derrubam implementações
Resto 0 quase sempre vira DV 0, mas resto 1 diverge por banco: Banco do Brasil usa X, Bradesco usa 0, Santander usa 1. Ignorar essa diferença gera contas com DV errado que passam em testes unitários simples e quebram em validação real.
function mod11(digits: number[], weights: number[]): number {
const sum = digits.reduce((acc, digit, i) => acc + digit * weights[i % weights.length], 0);
return sum % 11;
}
function mod10(digits: number[]): number {
const sum = digits
.reverse()
.reduce((acc, digit, i) => {
const product = digit * (i % 2 === 0 ? 2 : 1);
return acc + (product > 9 ? Math.floor(product / 10) + (product % 10) : product);
}, 0);
return sum % 10;
}---
Banco do Brasil (001): mod-11 na conta de 6 dígitos
Regra oficial: resto 0 → DV 0, resto 1 → DV X
O BB aplica mod-11 com pesos de 2 a 9 sobre os dígitos da conta (sem o DV). O resultado 11 - resto é o DV — exceto quando o resto é 0 (DV = 0) ou 1 (DV = X).
Contas com 8 dígitos — a variação que a maioria esquece
Correntistas mais antigos têm contas de 8 dígitos. A lógica é idêntica; o que muda é o padding com zeros à esquerda antes de calcular. Sempre normalize para 8 dígitos antes de aplicar os pesos.
Implementação em TypeScript com tipos estritos
export function calcDVBancoDoBrasil(conta: string): string {
const digits = conta.padStart(8, '0').split('').map(Number);
const weights = [9, 8, 7, 6, 5, 4, 3, 2];
const remainder = mod11(digits, weights);
if (remainder === 0) return '0';
if (remainder === 1) return 'X';
return String(11 - remainder);
}---
Bradesco (237): mod-11 com pesos 2 a 7
Sequência de pesos e ordem de aplicação
O Bradesco usa pesos de 2 a 7 (seis pesos) sobre os seis dígitos da conta, da direita para a esquerda. Se a conta tiver menos de seis dígitos, padeia com zeros à esquerda.
Resto 0 ou 1 → DV 0 (diferente do BB)
Quando o resto é 0 ou 1, o DV é 0. Para qualquer outro valor, DV = 11 - resto. Essa diferença em relação ao BB é sutil e costuma causar regressões quando se reutiliza código de um banco no outro.
Código TypeScript pronto para produção
export function calcDVBradesco(conta: string): string {
const digits = conta.padStart(7, '0').split('').map(Number);
const weights = [2, 3, 4, 5, 6, 7, 8];
const remainder = mod11(digits, weights);
if (remainder === 0 || remainder === 1) return '0';
return String(11 - remainder);
}DICA: Para testes com o Bradesco, gere também um CNPJ válido para a titularidade PJ. Use o gerador de CNPJ do FakeForge e combine com a conta gerada aqui.
---
Itaú (341): mod-10 na conta + agência composta
Concatenar agência e conta antes de calcular
O Itaú é o único entre os cinco grandes que usa mod-10, e faz algo diferente: concatena os quatro dígitos da agência com os cinco dígitos da conta antes de aplicar o algoritmo. O DV calculado é da combinação agência+conta, não da conta isolada.
Por que o Itaú usa mod-10 enquanto os outros usam mod-11
Decisão histórica de projeto — mod-10 é o mesmo algoritmo do código de barras FEBRABAN, então reaproveitam a implementação. Não há uma razão técnica que o torne superior ao mod-11 para esse caso de uso.
Implementação e casos de borda
export function calcDVItau(agencia: string, conta: string): string {
const combined = (agencia.padStart(4, '0') + conta.padStart(5, '0')).split('').map(Number);
const remainder = mod10(combined);
return remainder === 0 ? '0' : String(10 - remainder);
}Conta 00000 com qualquer agência é inválida e deve ser rejeitada antes de chegar ao cálculo. Adicione um guard no início da função se estiver validando entrada de usuário.
---
Caixa Econômica Federal (104): operação específica por tipo de conta
Contas 001/003/013/023 versus contas Poupança
A CEF classifica contas pelo código de operação — os três primeiros dígitos que antecedem o número da conta. Contas correntes (001, 003, 013, 023) e poupança (013, 023 com variações) têm algoritmos distintos. O código de operação precisa ser conhecido antes de calcular o DV.
Algoritmo CAIXA com peso crescente e tabela de substituição
Para contas correntes comuns, a CEF aplica mod-11 com pesos de 2 a 9. O ponto diferente é a tabela de substituição para restos específicos quando o tipo de operação é poupança.
Código com mapa de tipo de operação
const CAIXA_SAVINGS_OPS = new Set(['013', '023', '028', '003']);
export function calcDVCaixa(operacao: string, conta: string): string {
const digits = conta.padStart(11, '0').split('').map(Number);
const weights = [8, 7, 6, 5, 4, 3, 2, 9, 8, 7, 6];
const remainder = mod11(digits, weights);
if (CAIXA_SAVINGS_OPS.has(operacao)) {
if (remainder === 0) return '0';
if (remainder === 1) return '1';
return String(11 - remainder);
}
if (remainder === 0 || remainder === 1) return '0';
return String(11 - remainder);
}AVISO: A CEF atualiza a tabela de operações periodicamente. Antes de usar em produção, valide contra a especificação FEBRABAN vigente ou a documentação da CEF para correspondentes bancários.
---
Santander (033): mod-11 com pesos 2-9 e dígito fixo para resto 0
Diferença sutil em relação ao Bradesco
O Santander usa mod-11 com pesos de 2 a 9 — igual ao BB — mas trata resto 0 como DV 0 e resto 1 como DV 1. Nenhum DV X aqui.
Validação da agência (sempre 4 dígitos, sem DV próprio no Santander)
O Santander não tem DV de agência. A agência é sempre quatro dígitos sem caractere verificador. Se você receber um dado com cinco caracteres na agência, o quinto é provavelmente o DV da conta no formato antigo do banco, antes da migração para o sistema atual.
Implementação TypeScript
export function calcDVSantander(conta: string): string {
const digits = conta.padStart(9, '0').split('').map(Number);
const weights = [9, 8, 7, 6, 5, 4, 3, 2, 9];
const remainder = mod11(digits, weights);
if (remainder === 0) return '0';
if (remainder === 1) return '1';
return String(11 - remainder);
}---
Nubank, Inter e C6: contas digitais sem agência física
Estrutura de conta das fintechs — ISPB em vez de código de compensação
Fintechs usam o ISPB (Identificador do Sistema de Pagamentos Brasileiro) como identificador, não o código COMPE de três dígitos. O ISPB do Nubank é 18236120, do Inter é 00416968, do C6 é 31872495. Em integrações via PIX ou TED, o ISPB é o identificador correto.
Por que o dígito verificador é opcional ou inexistente nessas APIs
Contas digitais usam numeração sequencial interna sem algoritmo de verificação público documentado. O DV, quando presente, é apenas um campo de controle interno sem especificação aberta.
Como gerar dados de teste realistas para essas instituições
Para testes, gere um número de conta com 7 a 10 dígitos, use 0001 como agência (padrão dessas instituições) e deixe o campo de DV vazio ou 0. O endpoint /gerador-conta-bancaria do FakeForge já inclui Nubank, Inter e C6 com essa estrutura.
---
Montando um gerador unificado por código de banco (COMPE)
Mapa de estratégia por banco — o padrão Strategy em TypeScript
interface BankAccountStrategy {
calcDV(agencia: string, conta: string): string;
agenciaDigits: number;
contaDigits: number;
}
const STRATEGIES: Record<string, BankAccountStrategy> = {
'001': { calcDV: (_, c) => calcDVBancoDoBrasil(c), agenciaDigits: 4, contaDigits: 8 },
'237': { calcDV: (_, c) => calcDVBradesco(c), agenciaDigits: 4, contaDigits: 7 },
'341': { calcDV: calcDVItau, agenciaDigits: 4, contaDigits: 5 },
'033': { calcDV: (_, c) => calcDVSantander(c), agenciaDigits: 4, contaDigits: 9 },
};Gerando agência, conta e DV coerentes em uma só chamada
interface BankAccount {
bankCode: string;
agencia: string;
conta: string;
dv: string;
}
function randomDigits(n: number): string {
return Array.from({ length: n }, () => Math.floor(Math.random() * 10)).join('');
}
export function generateBankAccount(bankCode: string): BankAccount {
const strategy = STRATEGIES[bankCode];
if (!strategy) throw new Error(`Banco ${bankCode} sem estratégia registrada`);
const agencia = randomDigits(strategy.agenciaDigits);
const conta = randomDigits(strategy.contaDigits);
const dv = strategy.calcDV(agencia, conta);
return { bankCode, agencia, conta, dv };
}Fallback para bancos sem algoritmo documentado
Para bancos fora do mapa, gere um DV aleatório de um dígito e marque o objeto com dvVerified: false. Isso mantém a interface consistente sem gerar dados que pareçam válidos quando não são.
---
Validando contas geradas: testes com Jest
Casos felizes por banco e casos de borda
import { calcDVBancoDoBrasil, calcDVBradesco, calcDVItau, calcDVSantander } from './bank-dv';
describe('Banco do Brasil', () => {
it.each([
['12345678', '4'],
['00000001', 'X'],
['99999999', '0'],
])('conta %s → DV %s', (conta, expected) => {
expect(calcDVBancoDoBrasil(conta)).toBe(expected);
});
});
describe('Itaú — agência + conta concatenados', () => {
it('agência com zero à esquerda não altera resultado', () => {
expect(calcDVItau('0340', '12345')).toBe(calcDVItau('340', '12345'));
});
});Integração com o endpoint da FakeForge para geração em volume
Para gerar mil contas em batch sem implementar o gerador localmente, use a API REST do FakeForge:
curl "https://fakeforge.com.br/api/generate?type=bankAccount&quantity=1000&format=csv" \
-H "x-api-key: SEU_TOKEN"O CSV retornado inclui bankCode, agencia, conta e dv prontos para seed de banco de dados. Para mais de 100 chamadas por dia, veja os planos disponíveis.
---
Uso com LGPD: quando dados bancários fictícios são necessários
LGPD Art. 7º, IX — legítimo interesse e dados de teste
A LGPD Art. 7º, IX permite o tratamento de dados pessoais quando necessário para atender interesses legítimos do controlador. Para testes de integração bancária, o interesse legítimo é claro — mas o caminho mais limpo é não usar dados reais. Dados sintéticos gerados com algoritmos corretos eliminam o risco de exposição de titulares.
Diferença entre dado sintético e dado real anonimizado
Dado sintético nunca existiu. Dado anonimizado existiu e passou por processo de remoção de identificadores. Para fins de teste, dados sintéticos são superiores: sem risco residual de re-identificação, sem obrigação de registrar o tratamento como dado pessoal.
Por que gerar dados inválidos é pior do que usar dados reais (falha silenciosa)
Contas com DV errado passam em testes de formato mas falham silenciosamente em validações de negócio dos bancos. O sistema registra a transação, não retorna erro imediato, e o problema aparece horas depois na reconciliação. Dados sintéticos com DV correto detectam esses bugs no ambiente de desenvolvimento, onde o custo é zero.
---
Resumo
- Mod-11 é o padrão, mas cada banco trata restos 0 e 1 de forma diferente: BB usa
Xpara resto 1, Bradesco usa0, Santander usa1. - Itaú é o único entre os cinco grandes que usa mod-10 e concatena agência+conta antes de calcular.
- CEF exige o código de operação antes do cálculo — sem ele, não é possível determinar o algoritmo correto.
- Fintechs (Nubank, Inter, C6) não têm algoritmo de DV público; use agência
0001e DV0em dados de teste. - O padrão Strategy (interface
BankAccountStrategy+ mapa por código COMPE) permite adicionar novos bancos sem alterar a função geradora. - Para geração em volume sem manter o código localmente, o endpoint /api/generate exporta contas em JSON, CSV ou SQL com o gerador de conta bancária do FakeForge. Para CPF e CNPJ de titulares, use os geradores /gerador-cpf e /gerador-cnpj.
Perguntas frequentes
Como validar uma conta bancária existente em vez de gerar uma nova?+
Implemente a validação invertida: dado agência, conta e DV, recalcule o DV com a mesma estratégia e compare com o informado. Para Banco do Brasil, `calcDVBancoDoBrasil(conta) === dvInformado`. Se não baterem, rejeite. O padrão Strategy funciona em ambas direções — geração e validação.
Posso reutilizar o mesmo dígito verificador para múltiplas contas da mesma agência?+
Não. O DV é calculado a partir da sequência específica de dígitos da conta. Contas diferentes, mesmo agência, produzem DVs diferentes. Usar o mesmo DV viola a integridade do esquema. No padrão Strategy, DV é função pura da conta — sem nenhuma reutilização possível entre registros.
Como testo conta bancária de um banco fora da lista (ex: Banco Safra)?+
Gere agência e conta com dígitos aleatórios, deixe DV `0` ou fictício, marque com `dvVerified: false`. Em testes, mocke a validação ou pule. Para cobertura real, solicite especificação ao Banco Central. FakeForge inclui os cinco maiores; bancos menores requerem algoritmos específicos.
Qual a diferença entre validar DV isolado e validar a conta inteira no backend?+
Validar DV é verificação de formato local — confirma que segue o algoritmo. Validar conta inteira requer chamar a API do banco para confirmar existência, saldo, titularidade. São camadas distintas. Use DV para rejeitar dados inválidos antes de contatar o banco.
Se o FakeForge gera conta válida, posso depositar nela ou usar em produção?+
Não. Dados sintéticos passam na verificação matemática de DV mas são fictícios — não existem no banco. Usar em produção causará erro na transação. Use para testes locais, mocks, fixtures. Dados reais vêm de contas sandbox do banco, não do FakeForge.