← 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.