WysePayDocs

Webhooks

Seja avisado no seu servidor quando um pagamento é confirmado.

Um webhook é uma chamada que a WysePay faz para uma URL sua quando algo acontece, como um pagamento confirmado. É o jeito certo de saber que foi pago: chega em segundos e você não precisa consultar a API em loop.

Cadastrar

  1. No painel, vá em Desenvolvedores → Webhooks.
  2. Informe a URL (use https) e marque os eventos.
  3. Guarde o segredo que aparece: ele valida a assinatura.
  4. Use Testar para conferir se a sua URL responde.

Endpoints de teste (cadastrados com o modo teste ligado) só recebem eventos de teste, e os de produção só os reais.

Eventos

EventoQuandoCorpo
transaction.createdUm Pix foi gerado (API, painel ou link).Transação
transaction.paidO pagamento foi confirmado. Libere o pedido aqui.Transação
transaction.expiredO Pix venceu sem pagamento. Cancele o pedido ou gere outro Pix.Transação
dispute.createdO pagador contestou o pagamento pelo banco (MED).MED
dispute.respondedA sua defesa do MED foi enviada.MED
dispute.wonA contestação foi negada: o valor volta a ficar disponível.MED
dispute.lostA devolução foi confirmada: o valor voltou ao pagador.MED
withdrawal.createdUm saque foi pedido, pelo painel ou pela API.Saque
withdrawal.paidO saque chegou ao destino.Saque
withdrawal.partially_paidParte do saque não foi concluída e voltou ao saldo.Saque
withdrawal.failedO saque não foi feito e o valor voltou ao saldo.Saque
webhook.testVocê clicou em Testar no painel.{ message, sentAt }

Os eventos de transação mandam a mesma transação que a API devolve, incluindo o seu metadata. Use-o para achar o pedido no seu sistema.

O que chega

Um POST com o corpo em JSON e estes headers:

HeaderO que é
wysepay-eventO tipo do evento, como transaction.paid.
wysepay-signatureA assinatura, para você conferir que veio da WysePay.
wysepay-timestampQuando foi assinado, em milissegundos.
wysepay-delivery-idO id da entrega. É o mesmo nas novas tentativas automáticas.
wysepay-attemptO número da tentativa, de 1 a 6.

Validar a assinatura

A assinatura é um HMAC-SHA256, em hexadecimal, feito com o segredo do endpoint sobre o texto {wysepay-timestamp}.{corpo}. Calcule o mesmo no seu servidor e compare. Se não bater, recuse com 401.

Use o corpo exatamente como chegou

Assine o texto bruto da requisição, antes de transformar em objeto. Reescrever o JSON muda espaços e a ordem dos campos, e a assinatura deixa de bater.

import crypto from "node:crypto";
import express from "express";

const app = express();

// O corpo cru (Buffer), não o objeto já interpretado.
app.post("/webhooks/wysepay", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.header("wysepay-timestamp");
  const signature = req.header("wysepay-signature") ?? "";
  const expected = crypto
    .createHmac("sha256", process.env.WYSEPAY_WEBHOOK_SECRET)
    .update(`${timestamp}.${req.body}`)
    .digest("hex");

  const valid =
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  if (!valid) return res.sendStatus(401);

  const event = req.header("wysepay-event");
  const data = JSON.parse(req.body.toString("utf8"));
  if (event === "transaction.paid") {
    // Libere o pedido data.metadata.orderId (uma vez só: veja "Entregas repetidas").
  }
  res.sendStatus(200);
});

Responda rápido

Responda com qualquer status 2xx em até 8 segundos. Se o trabalho for demorado (e-mail, nota fiscal), guarde o evento, responda 200 e processe depois.

Novas tentativas

Se a sua URL não responder 2xx a tempo, a WysePay tenta de novo depois de 1 minuto, 5 minutos, 30 minutos, 2 horas e 6 horas: até 6 tentativas no total. Em Webhooks, no painel, você vê cada entrega e a resposta do seu servidor, e pode usar Reenviar evento: ele cria uma entrega nova, com outro wysepay-delivery-id e uma assinatura nova.

Se todas as tentativas falharem, você pode ser avisado por e-mail (ligue em Configurações → Notificações).

Entregas repetidas

O mesmo evento pode chegar mais de uma vez (por exemplo, se a sua resposta se perdeu no caminho). Trate os eventos de forma idempotente: antes de liberar, confira se o pedido daquela transação (id) já foi liberado. O wysepay-delivery-id ajuda a reconhecer tentativas repetidas, mas um reenvio manual chega com um id novo.

Nesta página