Verificar assinatura

Cada webhook inclui um header X-PaysClub-Signature com uma assinatura HMAC-SHA256 do body. Use o secret do endpoint para verificar a autenticidade.

Sempre verifique a assinatura antes de processar um webhook. Não confie em webhooks sem validação.

Node.js

verify-webhook.js
const crypto = require("crypto");

function verifySignature(body, signature, secret) {
  const computed = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");

  // Comparação timing-safe
  return crypto.timingSafeEqual(
    Buffer.from(computed),
    Buffer.from(signature)
  );
}

// No seu endpoint:
app.post("/webhook", (req, res) => {
  const signature = req.headers["x-paysclub-signature"];
  const body = JSON.stringify(req.body);

  if (!verifySignature(body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }

  const { event, data } = req.body;
  console.log("Evento recebido:", event, data);

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

Python

verify_webhook.py
import hmac
import hashlib

def verify_signature(body: bytes, signature: str, secret: str) -> bool:
    computed = "sha256=" + hmac.new(
        secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(computed, signature)

# No seu endpoint Flask:
@app.route("/webhook", methods=["POST"])
def webhook():
    signature = request.headers.get("X-PaysClub-Signature")
    if not verify_signature(request.data, signature, WEBHOOK_SECRET):
        return "Invalid signature", 401

    data = request.json
    print("Evento:", data["event"])
    return {"received": True}

Retentativas

Se seu endpoint retornar status diferente de 2xx, a PaysClub tentará reenviar até 3 vezes com backoff exponencial (5s, 30s, 2min).