Como enviar código de verificação (OTP) pela API de WhatsApp

Para enviar código de verificação pelo WhatsApp, o seu sistema gera o código, guarda só o hash com prazo de validade e usa a API apenas para entregar a mensagem. Quem valida é o seu backend, com limite de tentativas e de reenvios por número.

Quem faz o quê num fluxo de OTP

Um código de verificação serve para provar que a pessoa tem acesso àquele número naquele momento. Isso vale para cadastro, login sem senha, segundo fator e confirmação de operação sensível, como troca de e-mail ou saque. A tentação é procurar um endpoint pronto que gere e valide o código. Não faça isso depender do canal de entrega.

A divisão correta de responsabilidades é esta:

EtapaResponsável
Gerar o código com fonte aleatória seguraSeu backend
Guardar o hash, a validade e o contador de tentativasSeu backend
Entregar a mensagem no WhatsApp do usuárioAPI de WhatsApp
Comparar o código digitado e invalidar após o usoSeu backend
Bloquear abuso por número, IP e contaSeu backend

Assim, trocar de canal, somar SMS como alternativa ou mudar de fornecedor não mexe na lógica de segurança. A API de WhatsApp vira um transporte, que é o papel dela aqui.

Exemplo completo em Node

O trecho abaixo mostra as duas pontas: emitir e verificar. O armazenamento está abstraído em db, que pode ser Redis com expiração ou uma tabela com coluna de validade.

import { randomInt, createHash, timingSafeEqual } from 'node:crypto'
import { DApi } from 'd-api-sdk'

const dapi = new DApi({ apiKey: process.env.DAPI_API_KEY! })
const hash = (codigo: string) => createHash('sha256').update(codigo).digest()

export async function emitirCodigo(telefone: string) {
  const codigo = randomInt(0, 1_000_000).toString().padStart(6, '0')
  await db.otp.upsert(telefone, {
    hash: hash(codigo),
    expiraEm: Date.now() + 5 * 60_000,
    tentativas: 0,
  })
  await dapi.messages.sendText({
    sessionId: 'app-verificacao',
    to: telefone, // ex.: 5511999999999
    text: `${codigo} é o seu código de verificação do App. Ele expira em 5 minutos. Não compartilhe com ninguém.`,
  })
}

export async function verificarCodigo(telefone: string, digitado: string) {
  const registro = await db.otp.get(telefone)
  if (!registro || registro.expiraEm < Date.now()) return false
  if (registro.tentativas >= 5) return false
  await db.otp.incrementarTentativas(telefone)
  const ok = timingSafeEqual(hash(digitado), registro.hash)
  if (ok) await db.otp.remover(telefone) // uso único
  return ok
}

Repare que o código em texto puro só existe na memória durante o envio. Ele não vai para o banco nem para o log. Para os detalhes do SDK, veja o SDK Node.js e o guia de API de WhatsApp em Node.js.

Checklist de segurança

  • Aleatoriedade de verdade. Use crypto.randomInt ou equivalente. Nada de Math.random ou código derivado de horário.
  • Hash, nunca texto puro. Se o banco vazar, códigos em aberto viram acesso imediato.
  • Validade curta e uso único. Cinco a dez minutos, e o código morre na primeira verificação bem-sucedida.
  • Limite de tentativas por código. Cinco erros invalidam o código e exigem um novo envio.
  • Limite de envios por número. Por exemplo, um reenvio a cada 60 segundos e no máximo cinco por hora. Isso protege o usuário de spam e protege o seu número de parecer robô descontrolado.
  • Limite por IP e por conta, para barrar quem tenta disparar códigos para milhares de números diferentes.
  • Sem código em log. Registre que o envio aconteceu, com o telefone mascarado, nunca o código.
  • Mensagem curta e clara: código no início, validade e o aviso de não compartilhar.

Velocidade e disponibilidade do envio

Código que demora chega depois que o usuário desistiu. Algumas decisões ajudam:

  • Use uma sessão dedicada para verificação, separada de atendimento e de campanhas. Assim um problema num número de marketing não trava o login dos usuários.
  • Envie de forma síncrona, sem fila no meio. Aqui o usuário está olhando a tela, e a resposta da API diz na hora se houve erro.
  • Monitore o evento connection.status da sessão de verificação e alerte o time se ela sair de connected.
  • Ofereça SMS como alternativa depois de alguns segundos ou quando o envio falhar. A D-API tem API de SMS na mesma conta.

Um número usado só para códigos, com volume que acompanha o uso real do app, tem perfil de envio saudável. Mesmo assim, vale conhecer os cuidados de como evitar banimento.

Quando usar o template de autenticação da API oficial

Na API oficial da Meta, código de verificação tem uma categoria própria de template, a de autenticação. O template precisa ser aprovado antes do uso, e a cobrança da Meta é por mensagem, com valor que varia por categoria e país. Em troca, o envio sai por um número verificado da empresa.

Faz sentido considerar a oficial quando:

  • O volume de códigos é muito alto e vem de usuários que nunca conversaram com a empresa.
  • O setor é regulado e a empresa exige o canal oficial por política interna.
  • A marca verificada no remetente é importante para o usuário confiar no código.

Na D-API, uma conexão oficial envia o template pela rota messages/send/template, com o código em bodyVariables. O resto da aplicação continua o mesmo. Veja a API oficial de WhatsApp e a comparação em API oficial vs não oficial. Código de verificação é um tipo de notificação transacional, com exigência maior de velocidade. O trial de 3 dias permite testar o fluxo inteiro com um número real.

Perguntas frequentes

A API de WhatsApp gera o código de verificação para mim?

Não, e isso é bom. O código deve nascer e ser validado no seu sistema, que é quem conhece o usuário e a regra de expiração. A API só entrega a mensagem com o código no WhatsApp da pessoa.

WhatsApp é mais seguro que SMS para enviar OTP?

O WhatsApp tem criptografia de ponta a ponta e não depende da operadora, o que elimina alguns riscos do SMS, como interceptação na rede. Mas a segurança do fluxo continua dependendo de como o seu sistema gera, guarda e expira o código.

Quantos dígitos e quanto tempo de validade o código deve ter?

Seis dígitos numéricos é o padrão mais usado, fácil de digitar e difícil de adivinhar com limite de tentativas. Para login e cadastro, cinco a dez minutos de validade costuma ser suficiente.

E se o número do usuário não tiver WhatsApp?

Tenha um canal alternativo. A D-API também envia SMS pela mesma conta, então o seu sistema pode oferecer receber por SMS quando o envio pelo WhatsApp falhar ou quando o usuário pedir.

Preciso de template para enviar código pela API oficial?

Sim. Na API oficial, mensagens de código entram na categoria autenticação e precisam de template aprovado pela Meta. Na API não oficial o código vai como texto comum, sem aprovação prévia.

Teste a API de WhatsApp da D-API

Trial de 3 dias com acesso completo. Sem cartão, sem fidelidade.