WPPAPI
Blog

Como migrar da Evolution API para a WPPAPI sem parar a operação

·Equipe WPPAPIevolution apimigraçãonode.js

Quase todo time que roda Evolution API self-hosted chega no mesmo ponto: o software é ótimo, mas a operação cansa. Sessão que cai às 23h, update que muda o formato do payload, VPS que precisa de mais RAM depois da terceira instância. Se você decidiu trocar a operação por uma plataforma gerenciada, a boa notícia é que a migração é mecânica — os conceitos são os mesmos, muda a superfície da API.

Este post é o roteiro que usamos com quem vem da Evolution: mapa de rotas, um adaptador de 20 linhas para não reescrever seu código e a tradução dos webhooks.

O que muda (e o que não muda)

Não muda o modelo mental: você cria uma instância, conecta um número por QR Code, envia por REST e recebe eventos por webhook. Nada de aprovação da Meta, nada de template pré-aprovado.

Muda três coisas concretas:

  1. Autenticação. A Evolution usa o header apikey global ou por instância. Na WPPAPI o par instanceId + token vai na própria URL (/instances/{id}/token/{token}/...) ou, se preferir manter a URL limpa, no header Client-Token / Instance-Token.
  2. Nomes das rotas e dos campos. number/text viram phone/message, e cada tipo de mídia tem endpoint próprio.
  3. Quem opera. Você deixa de manter VPS, backup e atualização — que é o motivo de estar migrando.

Mapa de endpoints

Base da WPPAPI: https://api.wpp-api.com. Prefixo de toda rota: /instances/{instanceId}/token/{token}.

Evolution API (v2) WPPAPI Corpo na WPPAPI
POST /message/sendText/{instance} POST .../send-text { phone, message }
POST /message/sendMedia/{instance} (image) POST .../send-image { phone, image, caption }
POST /message/sendMedia/{instance} (document) POST .../send-file { phone, document, fileName }
POST /message/sendMedia/{instance} (video) POST .../send-video { phone, video, caption }
áudio / PTT POST .../send-voice { phone, audio }
POST /message/sendLocation/{instance} POST .../send-location { phone, latitude, longitude, title }
POST /message/sendContact/{instance} POST .../send-contact { phone, contacts }
GET /instance/connect/{instance} GET .../qr-code
GET /instance/connectionState/{instance} GET .../status
POST /chat/whatsappNumbersExists GET .../check-number?phone=...
GET /chat/findChats GET .../chats
/group/* GET/POST .../groups veja os docs

As rotas exatas da Evolution variam entre versões — confira as suas antes de trocar. Do lado da WPPAPI, além do básico existem enquete (send-poll), lista (send-list), botões (send-buttons), figurinha (send-sticker), reação (PUT .../reaction), edição (PUT .../messages/edit), encaminhamento (forward), presença de digitação (typing/start) e download de mídia (GET .../media/{messageId}). A referência completa está nos docs.

Nos campos de mídia você pode passar uma URL direta (image: "https://...") ou o objeto file com base64: { file: { data: "<base64>", mimetype: "application/pdf", filename: "boleto.pdf" } }. Limite de 100 MB por arquivo.

Adaptador em Node.js: não reescreva seu código

Se sua aplicação já tem dezenas de chamadas espalhadas, o caminho mais rápido é um shim que preserva a assinatura das funções que você já usa:

const BASE = "https://api.wpp-api.com";
const { WPP_INSTANCE, WPP_TOKEN } = process.env;

async function call(path, body, method = "POST") {
  const res = await fetch(
    `${BASE}/instances/${WPP_INSTANCE}/token/${WPP_TOKEN}/${path}`,
    {
      method,
      headers: { "Content-Type": "application/json" },
      body: body ? JSON.stringify(body) : undefined,
    },
  );
  if (!res.ok) throw new Error(`WPPAPI ${path}: ${res.status}`);
  return res.json();
}

// mesma assinatura do seu wrapper antigo da Evolution
export const sendText = (number, text) =>
  call("send-text", { phone: number, message: text });

export const sendMedia = (number, { media, caption, fileName, mediatype }) =>
  call(
    mediatype === "document" ? "send-file" : `send-${mediatype}`,
    { phone: number, [mediatype === "document" ? "document" : mediatype]: media, caption, fileName },
  );

Se preferir tipagem e retry prontos, o SDK oficial wppapi-sdk está no npm e cobre as mesmas rotas.

Webhooks: de messages.upsert para received

Aqui está a maior diferença — e a maior economia de código. A Evolution entrega o payload cru do Baileys, então você aprendeu a escavar data.message.conversation, data.message.extendedTextMessage.text, e por aí vai. A WPPAPI normaliza antes de entregar:

{
  "event": "received",
  "wahaEvent": "message",
  "instanceId": "inst_abc123",
  "timestamp": "2026-07-27T14:03:11.482Z",
  "data": {
    "from": "5511999999999",
    "chatId": "5511999999999",
    "body": "quero a segunda via do boleto",
    "type": "chat",
    "fromMe": false
  }
}

Ou seja: data.key.remoteJiddata.from, data.message.conversationdata.body, data.key.fromMedata.fromMe. Seu roteador de palavra-chave encolhe bastante.

Cada entrega vai assinada. O header X-WPPAPI-Signature traz o HMAC-SHA256 em hex do corpo cru da requisição, com o segredo da instância:

import crypto from "crypto";

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const expected = crypto
    .createHmac("sha256", process.env.WPP_WEBHOOK_SECRET)
    .update(req.body)
    .digest("hex");
  const got = req.headers["x-wppapi-signature"];
  if (!got || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got))) {
    return res.sendStatus(401);
  }
  const evt = JSON.parse(req.body);
  // ...
  res.sendStatus(200);
});

Se seu endpoint cair, a plataforma tenta 4 vezes com backoff exponencial antes de mandar o evento para a dead-letter queue — que fica visível no painel, com payload e último erro, para você reprocessar. O passo a passo completo está no guia de webhooks em Node.js.

Roteiro de corte sem downtime

  1. Suba a instância nova em paralelo, com um número secundário, e aponte o webhook para um endpoint de staging.
  2. Rode o adaptador em modo sombra: envie por Evolution como sempre e, para uma fatia pequena do tráfego, também pela WPPAPI. Compare respostas e latência por um ou dois dias.
  3. Migre a leitura antes da escrita. Reaponte primeiro os webhooks (com o handler novo aceitando os dois formatos), depois vire os envios.
  4. Reconecte o número principal. Aqui há um QR Code novo — o WhatsApp permite múltiplos dispositivos, mas planeje uma janela de baixo movimento. Não migre número quente em segunda-feira de manhã.
  5. Desligue a VPS só depois de uma semana estável. Backup do banco antes, sempre.

Quando não migrar

Sendo honesto: se você tem requisito rígido de soberania de dados, equipe de infra ociosa ou precisa modificar o comportamento do cliente WhatsApp no código, a Evolution self-hosted continua sendo a escolha certa. E qualquer API não oficial — a nossa inclusive — carrega risco de banimento se você tratar o canal como lista de disparo. Migrar de plataforma não muda isso; boas práticas anti-ban mudam.

Se o que te incomoda é a operação, e não a tecnologia, o teste é barato: 3 dias grátis, sem cartão. Suba o adaptador acima, aponte 10% do tráfego e veja se a diferença aparece.

Coloque em prática

3 dias grátis, sem cartão — API, webhooks e Chatwoot inclusos.

Testar 3 dias grátis