← Voltar ao blog

Conta corrente em Node.js: calculando o dígito verificador por banco

·14 min de leitura

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 X para resto 1, Bradesco usa 0, Santander usa 1.
  • 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 0001 e DV 0 em 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.

Achou útil? Compartilha: