Webhooks
O Paygrid notifica seu servidor quando um pagamento muda de status — sem você precisar consultar a cada segundo.
1. Crie um endpoint
curl -X POST https://api.paygrid.tech/v1/webhooks/endpoints \
-H "X-Api-Key: sk_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"url": "https://sua-loja.com/webhooks/paygrid"
}'
O endpoint recebe todos os tipos de evento. Não há
assinatura por tipo: filtre pelo campo type do seu lado.
secret (whsec_…) uma única vez.
Guarde-o: é usado para verificar a assinatura de cada evento recebido.
2. Formato do evento
{
"type": "payment.approved",
"data": {
"status": "approved",
"method": "pix",
"trackingId": "3f2a9c1e-7b40-4d6a-9e21-5c8f0a1b2d3e",
"workflowId": "22222222-2222-2222-2222-222222222222",
"installments": 1,
"occurredAt": "2026-09-18T14:21:40.000-03:00",
"paymentId": "5183e61a-d1e4-5624-8674-536b05cc6f0e",
"transactionId": "e01663ce-bef5-4cd2-9339-13b1ccebb77b",
"executionId": "e01663ce-bef5-4cd2-9339-13b1ccebb77b",
"reference": "pedido-4472",
"amount": "1990",
"currency": "BRL",
"provider": "pagarme",
"providerTransactionId": "ch_nJdVwgGilHR9w8Mb"
},
"id": "evt_f7e92b1f-1a4c-4065-8fa9-178ec82fc5b5",
"apiVersion": "2026-08-01",
"createdAt": "2026-09-18T14:22:11.482-03:00",
"eventVersion": "3"
}
idé o mesmo em toda retentativa e todo reenvio — deduplique por ele.amounteeventVersionchegam como string, para não perder precisão em JavaScript. Converta antes de comparar.createdAtvem no fuso de Brasília (-03:00), para que um evento às 23h30 caia no dia certo.methodécardoupix, e fica ausente em cobranças anteriores a agosto de 2026.occurredAté quando o dinheiro de fato se moveu, segundo o provedor — o pagamento, ou o estorno. Concilie por ele, e não pelocreatedAt: os dois podem divergir, e ocreatedAté só quando o evento foi emitido. Fica ausente quando o provedor não informa a hora (numa recusa, por exemplo).trackingIdé o mesmo devolvido na criação da cobrança (POST /v1/transactions). É o identificador a nos enviar ao reportar um problema.workflowIdé o fluxo que processou a cobrança, o mesmo informado na criação.- Campo sem valor não é enviado — trate ausência como "não informado". A ordem das chaves não faz parte do contrato.
3. Tipos de evento
| Evento | data.status | Quando |
|---|---|---|
payment.pending | pending | Aguardando — o Pix ainda não foi pago, ou o provedor ainda não decidiu. |
payment.action_required | action_required | O comprador precisa agir (autenticação 3DS, por exemplo). |
payment.approved | approved | Pagamento aprovado. |
payment.declined | declined | Recusado pelo provedor. |
payment.cancelled | cancelled | Cancelado antes da captura — inclusive o Pix que venceu sem pagamento (failureReason: "pix_expirado" no pagamento). |
payment.refunded | refunded | Estornado por completo — pela API ou direto no painel do provedor (ex. Pagar.me). |
payment.failed | not_charged | Falha técnica antes de chegar ao provedor. Nada foi cobrado, e é seguro tentar de novo. Não é recusa. |
payment.pending_reconciliation | pending_reconciliation | A cobrança chegou ao provedor e a resposta se perdeu. O resultado real chega num evento seguinte. Não cobre de novo: a primeira pode ter sido aprovada. |
- Um evento por mudança de status. O evento só sai quando o status muda; o mesmo status não é anunciado duas vezes (retentativas e reenvios à parte — esses repetem o mesmo
id). - Estorno parcial não gera evento. O pagamento segue
approvede só orefundedAmountmuda — vale também para estorno parcial feito no painel do provedor. Para detectá-lo, consulteGET /v1/payments/{paymentId}. - Motivo da recusa ou do cancelamento não vem no evento: consulte
failureReasonemGET /v1/payments/{paymentId}.
type, data.status e data.method
saíam com o nome interno do enum (EVENT_TYPE_PAYMENT_APPROVED,
PAYMENT_STATUS_APPROVED, PAYMENT_METHOD_CARD).
Eventos anteriores a essa data, e o reenvio deles, continuam nesse
formato. Se sua integração já estava no ar, aceite os dois por enquanto.
Conciliação: reconciliation.completed
Quando uma execução da conciliação
termina — concluida ou falhou —, chega um evento com o
resumo da execução. É um por execução: o id é
evt_reconciliation_<runId>, o mesmo em toda retentativa.
O data é outro, sem paymentId:
{
"type": "reconciliation.completed",
"data": {
"runId": "8c1f...",
"origin": "csv",
"state": "concluida",
"reconciled": 118,
"divergent": 2,
"notFound": 3,
"withError": 0,
"total": 123,
"startedAt": "2026-10-19T06:00:00Z",
"finishedAt": "2026-10-19T06:00:41Z"
},
"id": "evt_reconciliation_8c1f...",
"apiVersion": "2026-08-01",
"createdAt": "2026-10-19T03:00:42-03:00",
"eventVersion": "1"
}
Os detalhes ficam em GET /v1/reconciliation?runId=8c1f... e
GET /v1/reconciliation/runs/8c1f....
4. Verifique a assinatura
Cada evento chega com cabeçalho de assinatura HMAC-SHA256 usando o
secret. Nunca confie no evento sem verificar —
um evento forjado com URL/segredo de terceiro pode fingir uma aprovação.
examples/verify/ no repositório da API.
5. Entrega e retentativa
- Entrega assíncrona (não bloqueia a resposta da cobrança).
- Retentativas com backoff quando seu endpoint falha ou demora.
- Após várias tentativas, o evento vai para uma fila de dead-letter.
- Resposta
404é tentada até 3 vezes antes da dead-letter. Os demais4xx(exceto408,425e429) vão para a dead-letter na primeira resposta. - Histórico e reenvio:
GET /v1/webhooks/eventsePOST /v1/webhooks/events/{id}/redeliver.
6. Webhooks inbound (do provedor)
Quando o provedor (ex. Pagar.me) confirma um pagamento,
ele chama o Paygrid via POST /v1/providers/{hash}/webhook.
Você não precisa se preocupar com isso — o Paygrid consome, projeta o
status e dispara seu webhook de saída.