Skip to main content
Registre uma URL HTTPS e o SwytchPay faz POST nela quando um evento ocorre.

Registrar

POST /v1/webhooks
{ "name": "minha corretora", "url": "https://suacorretora.com/webhooks/swytch", "events": ["deposit.paid", "payout.paid"] }
A resposta traz o secret (whsec_…) uma única vez — use-o para validar a assinatura. Omita events para receber todos.

Eventos

deposit.paid · deposit.expired · payout.paid · payout.failed
{
  "event": "deposit.paid",
  "created_at": 1781319150,
  "environment": "test",
  "data": { "id": "dep_…", "external_id": "pedido-42", "status": "PAID", "amount_cents": 10000, "net_cents": 9650, "e2e_id": "E…" }
}

Verificar a assinatura

Cada entrega traz dois headers:
X-Swytch-Timestamp: 1781319150
X-Swytch-Signature: sha256=<hex>
A assinatura é HMAC-SHA256(secret, "{timestamp}.{corpo cru}"). Valide sobre o corpo cru (não re-serialize o JSON) e rejeite timestamps com mais de 5 minutos (anti-replay):
import { createHmac, timingSafeEqual } from "node:crypto"

function verify(rawBody, headers, secret) {
  const ts = Number(headers["x-swytch-timestamp"])
  if (Math.abs(Date.now() / 1000 - ts) > 300) return false
  const sig = (headers["x-swytch-signature"] || "").replace("sha256=", "")
  const expected = createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex")
  const a = Buffer.from(expected), b = Buffer.from(sig)
  return a.length === b.length && timingSafeEqual(a, b)
}

Entrega e idempotência

  • Responda 2xx em até 7s. Falhas são re-tentadas (2 tentativas imediatas + redelivery por até 24h).
  • O mesmo evento pode chegar mais de uma vez — implemente idempotência por data.id + event.
  • GET /v1/webhooks/:id/deliveries mostra o log de entregas (status, latência, tentativas).
  • POST /v1/webhooks/:id/test dispara um evento de exemplo assinado.