Pular para o conteúdo principal

Changelog

Histórico de mudanças relevantes na API REST e nos webhooks do wpp-gateway.

A API segue versionamento de URL: /v1/*. Breaking changes promovem para /v2/*. Adições não-breaking continuam em /v1/*.


Unreleased

Mudanças no main desde a v0.1.0. O que está no ar agora: GET /versao.

Adicionado

  • buttons no envio de template (POST /v1/messages, type: "template"). Parâmetros dos botões que levam valor no envio: url (sufixo da URL dinâmica e código do botão de OTP), copy_code (código do cupom) e quick_reply (payload). Ver Mensagens → template.
  • GET /versao — o commit que a instância serve ({ servico, commit, subidoEm }), sem autenticação. Serve para conferir versão contra versão antes de publicar um produto que depende de capacidade nova do gateway; /health só diz que o processo está de pé.
  • POST /v1/phones/:id/logout — reinicia o pareamento. Descarta a credencial e, para Baileys, reabre a sessão pedindo QR no mesmo comando: mesmo id, mesmo webhook. É a saída para o canal preso com credencial obsoleta (403, 411, 440 e o loop de 503 preservam a identidade, e nenhum QR é emitido), que antes só se resolvia apagando o phone. Não é preciso encadear reconnect: o logout já reabre, e um reconnect concorrente se junta ao reset.
  • GET /v1/phones/:id/qrcode responde 425 PAIRING_IN_PROGRESS com o phone em CONNECTING (socket subindo com credencial). Antes, nessa janela, o endpoint servia um QR já consumido — e o celular recusava com "verifique sua conexão". Trate como "aguarde". Passando de ~1 minuto, ofereça ao usuário o POST /:id/logout — nunca automático: uma reconexão legítima também passa disso, e o logout desvincula o aparelho.
  • channel:disconnected com reason: "PAIRING_RESET" quando o pareamento é reiniciado pelo /logout. Antes o reset saía como MANUAL_DELETE, o mesmo motivo do DELETE do phone, e as duas coisas não se distinguiam nem na auditoria nem para quem mostra o motivo na tela.

Mudado

  • Canal pareado reconectando aparece como CONNECTING, não mais PENDING_QR. O gateway decidia "tem credencial?" por creds.registered, que no Baileys 7 só vira true no pareamento por código — todo reconnect de canal pareado por QR era reportado como "aguardando QR". Quem alerta em PENDING_QR deixa de ver falso positivo a cada reconexão.
  • message:status failed agora identifica o erro. errors[0].code passa a trazer o código da Meta quando existe (132018, 131047, 131026, …) em vez de sempre 0, e errors[0].title passa a trazer o código semântico do gateway (META_BAD_REQUEST, INVALID_PTT_FORMAT, …) em vez da string fixa 'SEND_FAILED'. Quem detectava falha por title === 'SEND_FAILED' precisa usar status === 'failed', e quem for rotear deve usar code: title continua sendo o título textual da Meta quando a falha chega pelo webhook de status dela. Formato do array inalterado.
  • Recusa determinística da Meta não é mais retentada. Erros de envio com metaError.code em {132000, 132005, 132012, 132015, 132016, 132018, 131047, 131026} falham na 1ª tentativa. 132001 ficou de fora de propósito: é a janela em que a Meta ainda não propagou a aprovação, e nela o retry resolve. Antes queimavam 5 tentativas (~2 min) para chegar ao mesmo FAILED — que agora chega em segundos. Para esses erros o failedReason (GET /v1/messages/:id) passa a vir prefixado com o código do gateway ([META_BAD_REQUEST] …), como já acontecia com os demais erros terminais. Demais 400 da Meta (ex.: mídia ainda em processamento) seguem retentáveis.
  • POST /v1/templates com nome que já falhou volta a funcionar. Template recusado na hora pela Meta deixa a linha local em REJECTED sem metaTemplateId; reenviar com o mesmo (phoneId, name, language) agora reaproveita essa linha (mesmo id) em vez de responder 409 ALREADY_EXISTS. Template que existe na Meta — ou submissão do mesmo nome ainda em voo — continua dando 409.
  • PATCH /v1/templates/:id em template REJECTED sem metaTemplateId re-submete em vez de responder 409 TEMPLATE_NOT_SUBMITTED ("aguarde aprovação inicial") para um template que a Meta já tinha recusado. Linha em DRAFT (submissão em voo) continua respondendo 409, e messageSendTtlSeconds na re-submissão passa a ser recusado com 400 em vez de ignorado em silêncio.
  • messageId é o único identificador de mensagem exposto. O ID nativo do canal (wamid da Meta / key.id do Baileys) nunca é mais retornado. Operações de mensagem agora usam o messageId do gateway no path (POST /v1/messages/{messageId}/react, DELETE /v1/messages/{messageId}, etc.) — antes usavam o ID nativo. quotedMessageId passa a ser o messageId do gateway da mensagem citada.
  • Webhooks canônicos entre canais. message:received e message:status agora têm o mesmo shape em Baileys / WABA / Instagram. Removidos os campos whatsappMessageId, fromMe, mediaUrl/mediaStorageKey no topo, tracked e raw. Mídia inbound vem em media.downloadUrl. Status de message:status agora é lowercase: sent | delivered | read | failed | deleted.
  • GET /v1/messages/{id} não retorna mais whatsappMessageId.
  • Mídia: metaMediaId renomeado para mediaHandle (body de POST /v1/messages e resposta de POST /v1/media/upload).
  • Instagram: usa o envelope canônico. Identidade vem como from.canonicalKey = "igsid:<id>", type: "igsid". Read receipts chegam como message:status com status: "read" + watermark (sem messageId, pois IG é por watermark).

Corrigido

  • Botão de cupom (copy_code) passa a enviar { type: "coupon_code" }. Antes ia como text: a Meta aprovava o template e recusava o envio com 132018.
  • Botão quick_reply passa a enviar { type: "payload" } — mesmo defeito, mesmo sintoma.
  • template:status passa a ser emitido. Estava na referência de webhooks, no openapi e no SDK desde a v0.1.0, mas nada o publicava: aprovação e rejeição só se descobriam relistando os templates.
  • Webhook: a última retentativa (12h) passa a acontecer. A entrega fazia 8 tentativas e só usava 7 das 8 esperas da tabela, então a DLQ chegava em ~8h40 em vez de ~20h40. Agora são 9 tentativas (X-WppGateway-Attempt vai até 9), e o nextRetryAt da entrega mostra a espera que de fato será aplicada (mostrava a seguinte).
  • Docs — validação da assinatura. O header é sha256=<hex>; o exemplo em Node comparava hex puro, e o timingSafeEqual lançava erro por tamanho diferente. Quem copiou o exemplo não estava validando nada.
  • POST /v1/phones deixa de mandar Deprecation na criação de Baileys. O header é para o WABA por credenciais (legado; o sucessor é o Embedded Signup). Em Baileys, que só nasce por essa rota, era um aviso de descontinuação falso.
  • Docs — referência conferida contra o código. As cópias do repo e do site divergiam em 12 páginas; agora são iguais, e um teste no CI as mantém assim. No caminho foram corrigidos a tabela e a contagem de retry dos webhooks, o formato da resposta de identities/resolve (pn é JID), o pairing code (8 caracteres, não dígitos), credentials.verifyToken (opcional), a resposta de request-name-change ({ id }) e os motivos do smb-sync. A página Grupos, que só existia no site, passa a existir também no repo.

v0.1.0 — 2026-05-21

Release inicial pública do wpp-gateway.

Adicionado

  • Canais: Baileys (QR + pairing code), WABA (manual + Embedded Signup), Instagram (OAuth).
  • Messages: 15 tipos de conteúdo (text, image, video, audio, document, sticker, location, contact, button, list, template, cta_url, location_request, address_message, flow).
  • Operações de mensagem: react, edit, delete, read, typing.
  • Media: download via signed URL, upload Meta, resumable upload, TTL 7d com ACK pattern.
  • Webhooks: registro por phone, HMAC-SHA256, 8 retries com backoff exponencial, DLQ, replay manual.
  • Events SSE: /v1/events/stream para dashboards real-time.
  • WABA Templates: CRUD + Meta sync, suporte a carousel, OTP, flow buttons, limited time offer.
  • WABA Calls: signaling SDP (make/accept/reject/hangup), recording upload.
  • WABA Groups: CRUD, participants, admins, join requests, send messages.
  • WABA Flows: CRUD + Meta sync, encryption RSA-OAEP para data_exchange, executions tracking.
  • Lookup: verificação de números (Baileys only).
  • Billing: invoices, Asaas (Pix/boleto/cartão), dunning automatizado.
  • Admin observability: audit logs, error events.
  • SDK React: Provider, hooks (usePhones, useChannelStatus, useQrCode), componentes (BaileysQRConnect, BaileysPairingConnect, WabaEmbeddedSignup, WabaManualConnect, ConnectChannelWizard).

Conhecidos

  • Scopes granulares de API key ainda não implementados (campo scopes aceito mas não validado).
  • Webhook template:status e call:* payloads ainda em estabilização — schemas podem evoluir.