Node.js

Adicionar a API do Vonage Verify ao backend

Como usar o SDK do servidor da Vonage

A Vonage disponibiliza uma API HTTP padrão nos bastidores. Isso significa que, em teoria, você poderia integrar o Verify enviando solicitações HTTP brutas você mesmo (por exemplo, com fetch, axios, etc.).

Então, por que usar o SDK do Vonage Node?

O uso do SDK é útil porque:

  • A autenticação é mais fácil e segura: o Verify utiliza autenticação baseada em JWT com uma chave privada. O SDK lida com o fluxo de assinatura corretamente, o que reduz a probabilidade de você cometer erros.

  • Código mais limpo: em vez de construir manualmente URLs e cabeçalhos e analisar formatos de resposta, você chama métodos como newRequest() e checkCode().

  • Melhor manutenção: quando a Vonage atualiza a API ou adiciona recursos, o SDK geralmente é atualizado para acompanhar essas mudanças.

  • Menos “armadilhas”: aspectos como a formatação das solicitações e os campos esperados são tratados de maneira consistente.

Vamos adicionar o SDK ao nosso app.js arquivo:

require("dotenv").config();

const fs = require("fs");
const express = require("express");
const cors = require("cors");

const { Auth } = require("@vonage/auth");
const { Verify2 } = require("@vonage/verify2");

const app = express();
const port = process.env.PORT || 3000;

app.use(cors());
app.use(express.json());

// Create Vonage credentials (JWT auth)
const credentials = new Auth({
  applicationId: process.env.VONAGE_APPLICATION_ID,
  privateKey: process.env.VONAGE_PRIVATE_KEY_PATH,
});

// Verify client (Verify API v2)
const verifyClient = new Verify2(credentials);

// Health check endpoint
app.get('/health', (req, res) => {
  res.json({ status: 'ok' });
});

// Run the server
app.listen(port, () => {
  console.log(`Backend listening on port ${port}`);
});

O que está acontecendo aqui?

  • O backend precisa comprovar à Vonage: “Tenho permissão para chamar essa API.”
  • A Vonage utiliza JWT (JSON Web Tokens) assinados pela sua chave privada para essa comprovação.
  • O SDK gera e anexa o JWT automaticamente sempre que faz uma chamada para a Vonage.

Iniciar verificação: POST /verification

Este endpoint inicia o processo de verificação. O aplicativo móvel envia uma solicitação ao seu backend com um número de telefone. Em seguida, o seu backend solicita à Vonage que inicie uma solicitação de verificação.

O que acontece neste endpoint?

  1. O usuário insere seu número de telefone no aplicativo móvel.
  2. O aplicativo móvel envia o número de telefone para o seu backend.
  3. Seu backend inicia uma solicitação de Verify:
    • primeiras tentativas Autenticação silenciosa
    • se isso não puder ser concluído, recorre a SMS
app.post("/verification", async (req, res) => {
  const { phone } = req.body || {};

  if (!phone) {
    return res.status(400).json({ error: "Phone number is required." });
  }

  try {
    const result = await verifyClient.newRequest({
      brand: "DemoApp",
      workflow: [
        { channel: "silent_auth", to: phone },
        { channel: "sms", to: phone },
      ],
    });

    return res.json({
      request_id: result.requestId,
      check_url: result.checkUrl,
    });
  } catch (error) {
    const status = error?.response?.status || 500;
    const details = error?.response?.data || error?.message;

    console.error("Vonage Verify newRequest failed:", details);

    return res.status(status).json({
      error: "Failed to start verification",
      details: typeof details === "string" ? details : undefined,
    });
  }
});

Compreensão request_id e check_url:

  • request_id: um identificador único para esta tentativa de verificação. Pense nisso como um “número de recibo” para a verificação.

  • check_url: usado para autenticação silenciosa. Seu backend retorna essa URL para o aplicativo móvel. O aplicativo móvel a acessa para comprovar que “essa solicitação está vindo da rede móvel do número de telefone”.

Verifique o código de verificação: POST /check-code

Se a autenticação silenciosa falhar ou não estiver disponível, a Vonage recorrerá ao SMS e o usuário receberá um código. O aplicativo móvel envia o código para o seu backend juntamente com o request_id.

app.post("/check-code", async (req, res) => {
  const { request_id, code } = req.body || {};

  if (!request_id || !code) {
    return res.status(400).json({ error: "request_id and code are required." });
  }

  try {
    const status = await verifyClient.checkCode(request_id, code);

    return res.json({
      verified: status === "completed",
      status,
    });
  } catch (error) {
    const status = error?.response?.status || 400;
    const details = error?.response?.data || error?.message;

    return res.status(status).json({
      error: "Failed to check code",
      details: typeof details === "string" ? details : undefined,
    });
  }
});

Callbacks

Um callback (também chamado de webhook) é uma URL no seu backend que um serviço externo (Vonage) pode acessar para notificá-lo sobre eventos.

Em vez de seu backend ficar constantemente consultando a Vonage: “O Silent Auth já terminou? E agora? E agora?”

A Vonage pode enviar o resultado para você: “A autenticação silenciosa foi concluída. Aqui está o status final.”

Essa notificação push é o callback.

Por que os callbacks são úteis neste caso? A autenticação silenciosa pode demorar e ser concluída de forma assíncrona. Usar um callback significa:

  • Seu backend não precisa consultar o Vonage repetidamente
  • Você recebe um evento definitivo quando a verificação muda de estado
  • Ele se adapta melhor a sistemas reais

Para configurar a URL de retorno de chamada no Painel, abra o Painel da Vonage:

  1. Acessar Applications
  2. Selecione seu aplicativo → Editar
  3. Encontrar o Registro de Rede
  4. Ativar Verify (SA)
  5. Defina a URL de retorno de chamada (onde seu servidor fica à espera), por exemplo:

https://your-domain.com/callback

Nota: Se você estiver executando o programa localmente, a Vonage não conseguirá acessá-lo http://localhost:3000. Você precisará de uma URL pública (geralmente um túnel como ngrok).

Para implementar o callback, adicione um novo método à sua aplicação Express da seguinte maneira:

app.post("/callback", (req, res) => {
  console.log("Callback received:", req.body);
  return res.status(200).json({ ok: true });
});

Por enquanto, registramos o evento para que você possa ver o que a Vonage envia. Na próxima seção, vamos ampliar essa funcionalidade para armazenar o estado e fazer com que o aplicativo móvel reaja a essas atualizações.

Adicionar um estado na memória

Um fluxo de verificação não se resume a “uma solicitação e pronto”. Ele possui um ciclo de vida:

  • começou
  • em espera (autenticação silenciosa / SMS)
  • concluído ou reprovado/vencido

Se você não armazenar o estado em lugar algum, seu backend não terá registro do que aconteceu, e:

  • /callback só consegue registrar dados (o que não é muito útil)
  • O aplicativo não consegue determinar com precisão o status atual
  • A depuração se torna um tormento (“funcionou uma vez, depois não funcionou mais…”)

Uma loja oferece a você uma única fonte de informação confiável.

Em ambiente de produção, você usaria um banco de dados (por exemplo, Postgres/Redis), mas, para o tutorial, podemos simplesmente usar um Map.

Passo 1: Crie a loja com um Map

No Node.js, um Map é uma maneira fácil de armazenar pares chave/valor na memória.

Adicione isso perto do início do seu app.js:

// In-memory store for tutorial purposes:
// request_id -> verification state
const verificationStore = new Map();

Adicione uma função auxiliar para validar os campos obrigatórios do corpo da solicitação. Adicione-a logo abaixo do verificationStore declaração:

function requireFields(obj, fields) {
  for (const f of fields) {
    if (!obj || obj[f] == null || obj[f] === "") return f;
  }
  return null;
}

Isso retorna o nome do primeiro campo ausente, ou null se todos os campos estiverem presentes.

Cada entrada será identificada por request_id.

Uma entrada típica poderia ser assim:

{
  "phone": "+34600111222",
  "status": "started",
  "createdAt": "2026-02-02T11:22:00.000Z",
  "updatedAt": "2026-02-02T11:22:00.000Z"
}

Etapa 2: Salvar o estado inicial ao criar uma verificação

Quando você ligar verifyClient.newRequest(...) em /verification, você recebe um request_id.

Essa é a chave perfeita para armazenar o estado inicial.

Dentro do seu /verification ponto final, logo depois de obter result:

verificationStore.set(result.requestId, {
  phone,
  status: "started",
  createdAt: new Date().toISOString(),
  updatedAt: new Date().toISOString(),
});

Agora, o backend “lembra” que uma verificação foi iniciada.

Etapa 3: Atualizar o estado quando a função de retorno de chamada receber eventos

Um callback (webhook) é quando a Vonage informa ao seu backend: “Algo mudou. Aqui está a nova situação.”

Em vez de apenas registrar a carga útil, atualizamos o estado armazenado:

app.post("/callback", (req, res) => {
  const { request_id, status } = req.body || {};
  if (!request_id) return res.status(400).json({ error: "Missing request_id" });

  const current = verificationStore.get(request_id) || {
    phone: null,
    status: "unknown",
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    lastEvent: null,
  };

  const updated = {
    ...current,
    status: status || current.status,
    updatedAt: new Date().toISOString(),
    lastEvent: req.body,
  };

  verificationStore.set(request_id, updated);

  return res.status(200).json({ ok: true });
});

As entregas de webhooks podem ser repetidas, o que significa que você pode receber o mesmo evento várias vezes. Atualizar a loja dessa forma é, naturalmente, idempotente: definir o mesmo status novamente não causa nenhum problema.

Etapa 4: Adicionar um endpoint de status para o aplicativo móvel

Agora podemos disponibilizar um endpoint simples que o aplicativo possa chamar para verificar o estado atual:

app.get("/status/:request_id", (req, res) => {
  const { request_id } = req.params;
  const entry = verificationStore.get(request_id);

  if (!entry) return res.status(404).json({ error: "Unknown request_id" });

  return res.json({
    request_id,
    status: entry.status,
    updated_at: entry.updatedAt,
  });
});

Isso é especialmente útil para a autenticação silenciosa, pois o aplicativo pode fazer consultas a cada 1–2 segundos por um curto período, em vez de ficar esperando sem saber o que vai acontecer.

Etapa 5: Adicionar POST /next

O /next O endpoint instrui a Vonage a pular o canal atual do fluxo de trabalho e passar para o próximo. No nosso caso, isso significa pular a autenticação silenciosa e enviar um SMS imediatamente.

Isso é útil no aplicativo para Android quando a solicitação de autenticação silenciosa falha (problemas de rede, erro no SDK etc.) — em vez de esperar cerca de 20 segundos até que o tempo limite da Vonage expire naturalmente, o aplicativo chama a função /next e o usuário recebe um SMS imediatamente.

app.post("/next", async (req, res) => {
  try {
    const missing = requireFields(req.body, ["requestId"]);
    if (missing) {
      return res.status(400).json({ error: `Field '${missing}' is required.` });
    }

    const { requestId } = req.body;

    const entry = verificationStore.get(requestId);
    if (!entry) {
      return res.status(404).json({ error: "Unknown request_id" });
    }

    console.log("Moving to next workflow (SMS) for:", requestId);

    // Call Vonage to move to next workflow
    const result = await verifyClient.nextWorkflow(requestId);
    console.log("Vonage nextWorkflow result:", result);

    // Update last event
    const updated = {
      ...entry,
      updatedAt: new Date().toISOString(),
      lastEvent: { source: "next_workflow", result },
    };
    verificationStore.set(requestId, updated);

    return res.status(200).json({ ok: true });
  } catch (error) {
    const status = error?.response?.status || 500;
    const details = error?.response?.data || error?.message;

    console.error("Error /next:", details);
    return res.status(status).json({
      error: "Failed to move workflow",
      details: typeof details === "string" ? details : undefined,
    });
  }
});

Observação: Se a opção /next falhar, isso não é grave. A Vonage voltará automaticamente para o SMS após o tempo limite da autenticação silenciosa. O aplicativo para Android deve exibir a tela de inserção de SMS, independentemente de essa chamada ter sido bem-sucedida ou não.