Webhooks

Webhooks avisam o seu sistema quando algo acontece, como "pagamento recebido" ou "devolvido". Venha a venda de qual conta vier, o aviso tem sempre o mesmo formato.

Adicionar um endereço

Em Webhooks → Adicionar endereço, coloque a URL do seu sistema (precisa ser https://) e escolha os avisos que quer receber.

Os avisos

Aviso Quando
payment.processing em análise (cartão), ainda sem resposta do banco
payment.succeeded o cliente pagou
payment.failed foi recusado
payment.created a cobrança foi criada
payment.canceled venceu ou você cancelou
payment.refunded devolvido por completo
payment.partially_refunded devolvido em parte
refund.created uma devolução foi pedida, ou feita direto no painel da conta
refund.updated a conta confirmou ou recusou uma devolução
reconciliation.completed a conferência do dia terminou
dispute.created o cliente contestou (MED ou chargeback)
dispute.updated a contestação mudou, por exemplo, você respondeu
dispute.closed a contestação terminou: ganha, perdida ou cancelada
subscription.created um Pix Automático foi criado e espera o cliente
subscription.activated o cliente aprovou o Pix Automático
subscription.refused o cliente não aprovou, ou o banco não confirmou
subscription.canceled o Pix Automático foi cancelado (por você ou pelo cliente)
subscription.expired chegou a data de fim
payout.created um saque foi pedido
payout.updated o saque está a caminho, ou a conta ainda não confirmou (uncertain: true)
payout.paid o dinheiro chegou ao destino
payout.failed a conta recusou ou o banco devolveu; veja failure_reason
payout.canceled o saque foi cancelado antes de sair
subaccount.created uma subconta foi criada (pelo painel ou pela API). Se não reconhecer, confira em Subcontas
subaccount.updated a situação de uma subconta mudou: aprovada, recusada, bloqueada
payout_destination.created o dono salvou uma chave Pix para saques. Se não foi alguém da equipe, remova em Saques

O que chega

{
  "id": "evt_3Jd9...",
  "type": "payment.succeeded",
  "created": 1760000000,
  "data": {
    "object": { "id": "pay_...", "status": "succeeded", "amount": 4990, "fee": 49, "net": 4941 }
  }
}

Responda com status 200 em até 8 segundos. Se o seu sistema não responder, a SuyPay tenta de novo depois de 1 min, 5 min, 30 min, 2 h, 6 h, 12 h e 24 h.

Confirmar que veio da SuyPay

Todo aviso traz o cabeçalho SuyPay-Signature. Confira com a chave de assinatura do endereço:

import crypto from 'node:crypto'

function veioDoSuyPay(corpo, cabecalho, chave) {
  const { t, v1 } = Object.fromEntries(cabecalho.split(',').map((p) => p.split('=')))
  const esperado = crypto.createHmac('sha256', chave).update(`${t}.${corpo}`).digest('hex')
  const recente = Math.abs(Date.now() / 1000 - Number(t)) < 300
  return recente && crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(v1))
}

Use o corpo exatamente como chegou, antes de transformar em JSON.