Visão Geral
Webhooks permitem que você receba notificações HTTP automáticas quando eventos importantes acontecem na sua conta, como pagamentos confirmados, reembolsos processados ou saques concluídos.Eventos Disponíveis
| Evento | Descrição |
|---|---|
payment_completed | Pagamento foi confirmado com sucesso |
payment_expired | Pagamento expirou sem confirmação |
refund_completed | Reembolso foi processado |
withdrawal_completed | Saque foi processado com sucesso |
withdrawal_failed | Saque foi rejeitado ou falhou |
withdrawal_reversed | Saque foi estornado pelo PSP |
balance_block_created | Bloqueio de saldo criado (MED/judicial/administrativo) |
balance_block_approved | Bloqueio aprovado — valor devolvido ao pagador |
balance_block_rejected | Bloqueio rejeitado — valor retorna ao lojista |
Estrutura do Payload
Todos os webhooks seguem a mesma estrutura base:{
"event": "payment_completed",
"eventId": "a0b78f10-c7f4-4f5d-98dd-3e36eafeb812",
"timestamp": "2026-01-11T19:03:28.280Z",
"data": {
// Dados específicos do evento
}
}
| Campo | Tipo | Descrição |
|---|---|---|
event | string | Tipo do evento |
eventId | string | ID único do evento (geralmente o ID da transação) |
timestamp | string | Data/hora do evento em formato ISO 8601 |
data | object | Dados específicos do evento |
Headers Enviados
Cada requisição de webhook inclui os seguintes headers:| Header | Descrição |
|---|---|
Content-Type | application/json |
X-Webhook-Signature | Assinatura HMAC-SHA256 do payload |
X-Webhook-Timestamp | Timestamp em milliseconds |
Validando a Assinatura
Cada webhook é assinado com HMAC-SHA256 para garantir autenticidade. Siga estes passos para validar:- Calcule a signing key:
SHA256(seu_webhook_secret)em hex - Calcule o HMAC-SHA256 do body da requisição usando a signing key
- Compare o resultado com o header
X-Webhook-Signatureusando comparação em tempo constante
import { verifyWebhookSignature, parseWebhook } from '@pague-dev/sdk-node';
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature'] as string;
const rawBody = req.body; // raw string body
if (!verifyWebhookSignature(rawBody, signature, 'seu_webhook_secret')) {
return res.status(401).send('Assinatura inválida');
}
const event = parseWebhook(rawBody);
if (!event) {
return res.status(400).send('Payload inválido');
}
// Processar o evento...
res.status(200).send('OK');
});
import { createHash, createHmac, timingSafeEqual } from 'node:crypto';
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature'] as string;
const rawBody = req.body; // raw string body
// 1. Calcular signing key (SHA256 do seu secret)
const signingKey = createHash('sha256')
.update('seu_webhook_secret')
.digest('hex');
// 2. Calcular HMAC-SHA256 do payload
const expected = createHmac('sha256', signingKey)
.update(rawBody)
.digest('hex');
// 3. Comparar em tempo constante
const isValid = timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(signature, 'hex'),
);
if (!isValid) {
return res.status(401).send('Assinatura inválida');
}
// Processar o evento...
res.status(200).send('OK');
});
Sempre use comparação em tempo constante (
timingSafeEqual) para evitar ataques de timing.
Nunca compare assinaturas com ===.Exemplos de Payload
payment_completed
Enviado quando um pagamento PIX é confirmado.{
"event": "payment_completed",
"eventId": "a0b78f10-c7f4-4f5d-98dd-3e36eafeb812",
"timestamp": "2026-01-11T19:03:28.280Z",
"data": {
"transactionId": "a0b78f10-c7f4-4f5d-98dd-3e36eafeb812",
"environment": "sandbox",
"amount": 100.21,
"feeAmount": 0.5,
"netAmount": 99.71,
"currency": "BRL",
"paymentMethod": "pix",
"status": "completed",
"completedAt": "2026-01-11T19:03:28.277Z",
"externalReference": "pedido-12345",
"e2eId": "E18189547202603160145ZYFfVx3jP8D",
"counterpartName": "Maria Silva",
"counterpartDocument": "12345678900",
"metadata": {
"orderId": "ORDER-12345",
"customerId": "CUST-67890"
}
}
}
| Campo | Tipo | Descrição |
|---|---|---|
transactionId | string | ID único da transação |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor total do pagamento |
feeAmount | number | Taxa cobrada |
netAmount | number | Valor líquido (amount - feeAmount) |
currency | string | Moeda (BRL) |
paymentMethod | string | Método de pagamento (pix) |
status | string | Status do pagamento (completed) |
completedAt | string | Data/hora da conclusão em ISO 8601 |
externalReference | string | Sua referência externa (opcional) |
e2eId | string | ID fim-a-fim da rede PIX (opcional, presente quando disponível) |
counterpartName | string | Nome do pagador conforme retornado pelo PSP (opcional) |
counterpartDocument | string | CPF/CNPJ do pagador conforme retornado pelo PSP (opcional, sem máscara) |
metadata | object | Metadados customizados enviados na criação do pagamento (opcional) |
payment_expired
Enviado quando um pagamento PIX expira sem confirmação.{
"event": "payment_expired",
"eventId": "payment_expired_d5e6f7a8-1234-5678-9abc-def012345678",
"timestamp": "2026-01-11T19:30:00.000Z",
"data": {
"transactionId": "d5e6f7a8-1234-5678-9abc-def012345678",
"environment": "sandbox",
"amount": 75.50,
"feeAmount": 0,
"netAmount": 0,
"currency": "BRL",
"paymentMethod": "pix",
"status": "expired",
"expiredAt": "2026-01-11T19:30:00.000Z",
"externalReference": "pedido-12345",
"metadata": {
"orderId": "ORDER-12345",
"customerId": "CUST-67890"
}
}
}
| Campo | Tipo | Descrição |
|---|---|---|
transactionId | string | ID único da transação |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor do pagamento |
feeAmount | number | Taxa cobrada (sempre 0 para pagamentos expirados) |
netAmount | number | Valor líquido (sempre 0 para pagamentos expirados) |
currency | string | Moeda (BRL) |
paymentMethod | string | Método de pagamento (pix) |
status | string | Status do pagamento (expired) |
expiredAt | string | Data/hora da expiração em ISO 8601 |
externalReference | string | Sua referência externa (opcional) |
metadata | object | Metadados customizados enviados na criação do pagamento (opcional) |
refund_completed
Enviado quando um reembolso é processado.{
"event": "refund_completed",
"eventId": "c92d45e6-8b33-4f12-a789-2e56f8901def",
"timestamp": "2026-01-11T19:22:15.456Z",
"data": {
"refundTransactionId": "c92d45e6-8b33-4f12-a789-2e56f8901def",
"originalTransactionId": "a0b78f10-c7f4-4f5d-98dd-3e36eafeb812",
"environment": "sandbox",
"amount": 50.00,
"feeAmount": 0.25,
"netAmount": 50.00,
"currency": "BRL",
"paymentMethod": "pix",
"status": "completed",
"refundedAt": "2026-01-11T19:22:15.400Z",
"externalReference": "pedido-12345",
"metadata": {
"orderId": "ORDER-12345",
"customerId": "CUST-67890"
}
}
}
Convenção do
netAmount em refund: representa o que o destinatário do evento (o cliente final) efetivamente recebe — ou seja, o valor cheio do reembolso. A taxa de reembolso é debitada separadamente do saldo do lojista. O custo total do refund para o lojista é amount + feeAmount.| Campo | Tipo | Descrição |
|---|---|---|
refundTransactionId | string | ID único da transação de reembolso |
originalTransactionId | string | ID da transação original que foi reembolsada |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor do reembolso |
feeAmount | number | Taxa do reembolso cobrada do lojista |
netAmount | number | Valor líquido recebido pelo cliente final (igual a amount) |
currency | string | Moeda (BRL) |
paymentMethod | string | Método de pagamento da transação original |
status | string | Status do reembolso (completed) |
refundedAt | string | Data/hora do reembolso em ISO 8601 |
externalReference | string | Sua referência externa do pagamento original (opcional) |
metadata | object | Metadados customizados do pagamento original (opcional) |
withdrawal_completed
Enviado quando um saque é processado com sucesso.{
"event": "withdrawal_completed",
"eventId": "e73775b5-70ee-4bad-be4c-4acff9890e27",
"timestamp": "2026-01-11T19:08:21.953Z",
"data": {
"withdrawalId": "e73775b5-70ee-4bad-be4c-4acff9890e27",
"environment": "sandbox",
"amount": 500.00,
"feeAmount": 2.50,
"netAmount": 497.50,
"currency": "BRL",
"status": "completed",
"completedAt": "2026-01-11T19:08:21.939Z",
"externalReference": "saque-empresa-001",
"e2eId": "E18189547202603160145ZYFfVx3jP8D",
"counterpartName": "João da Silva",
"counterpartDocument": "12345678900",
"metadata": {
"batchId": "BATCH-001"
}
}
}
| Campo | Tipo | Descrição |
|---|---|---|
withdrawalId | string | ID único do saque |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor do saque |
feeAmount | number | Taxa do saque |
netAmount | number | Valor líquido transferido |
currency | string | Moeda (BRL) |
status | string | Status do saque (completed) |
completedAt | string | Data/hora da conclusão em ISO 8601 |
externalReference | string | Sua referência externa enviada na criação do saque (opcional) |
e2eId | string | ID fim-a-fim da rede PIX (opcional, presente após confirmação do PSP) |
counterpartName | string | Nome do destinatário no banco de destino (opcional) |
counterpartDocument | string | CPF/CNPJ do destinatário (opcional, sem máscara) |
metadata | object | Metadados customizados do saque (opcional) |
withdrawal_failed
Enviado quando um saque é rejeitado ou falha.{
"event": "withdrawal_failed",
"eventId": "b84f12c3-9a21-4e67-bc88-1d45f6789abc",
"timestamp": "2026-01-11T19:15:42.123Z",
"data": {
"withdrawalId": "b84f12c3-9a21-4e67-bc88-1d45f6789abc",
"environment": "sandbox",
"amount": 1000.00,
"feeAmount": 5.00,
"netAmount": 995.00,
"currency": "BRL",
"status": "failed",
"failedAt": "2026-01-11T19:15:42.100Z",
"failureReason": "insufficient_funds",
"externalReference": "saque-empresa-001",
"e2eId": "E18189547202603160145ZYFfVx3jP8D",
"counterpartName": "João da Silva",
"counterpartDocument": "12345678900",
"metadata": {
"batchId": "BATCH-001"
}
}
}
| Campo | Tipo | Descrição |
|---|---|---|
withdrawalId | string | ID único do saque |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor do saque |
feeAmount | number | Taxa do saque |
netAmount | number | Valor líquido que seria transferido |
currency | string | Moeda (BRL) |
status | string | Status do saque (failed) |
failedAt | string | Data/hora da falha em ISO 8601 |
failureReason | string | Motivo da falha (insufficient_funds, invalid_account, etc.) |
externalReference | string | Sua referência externa enviada na criação do saque (opcional) |
e2eId | string | ID fim-a-fim da rede PIX (opcional, presente apenas se o saque chegou a ser processado pelo PSP) |
counterpartName | string | Nome do destinatário no banco de destino (opcional) |
counterpartDocument | string | CPF/CNPJ do destinatário (opcional, sem máscara) |
metadata | object | Metadados customizados do saque (opcional) |
withdrawal_reversed
Enviado quando um saque é estornado pelo PSP.{
"event": "withdrawal_reversed",
"eventId": "f12a34b5-6c78-9d01-ef23-456789abcdef",
"timestamp": "2026-01-11T20:00:00.000Z",
"data": {
"reversalTransactionId": "f12a34b5-6c78-9d01-ef23-456789abcdef",
"originalTransactionId": "e73775b5-70ee-4bad-be4c-4acff9890e27",
"environment": "sandbox",
"amount": 500.00,
"feeAmount": 0,
"netAmount": 500.00,
"currency": "BRL",
"paymentMethod": "pix",
"status": "completed",
"reversedAt": "2026-01-11T20:00:00.000Z",
"metadata": {
"batchId": "BATCH-001"
}
}
}
| Campo | Tipo | Descrição |
|---|---|---|
reversalTransactionId | string | ID único da transação de estorno |
originalTransactionId | string | ID do saque original que foi estornado |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor do estorno |
feeAmount | number | Taxa do estorno |
netAmount | number | Valor líquido do estorno |
currency | string | Moeda (BRL) |
paymentMethod | string | Método de pagamento (pix) |
status | string | Status do estorno (completed) |
reversedAt | string | Data/hora do estorno em ISO 8601 |
externalReference | string | Sua referência externa do saque original (opcional) |
metadata | object | Metadados customizados do saque original (opcional) |
balance_block_created
Enviado quando um bloqueio de saldo é criado (MED, judicial ou administrativo).{
"event": "balance_block_created",
"eventId": "d4e5f6a7-8b9c-0d1e-2f3a-456789abcdef",
"timestamp": "2026-01-11T19:30:00.000Z",
"data": {
"blockId": "d4e5f6a7-8b9c-0d1e-2f3a-456789abcdef",
"transactionId": "a0b78f10-c7f4-4f5d-98dd-3e36eafeb812",
"environment": "production",
"amount": 1500.00,
"currency": "BRL",
"blockType": "med",
"referenceNumber": "MED-2026-001234",
"reason": "Notificação de infração Pix recebida",
"status": "awaiting_response",
"createdAt": "2026-01-11T19:30:00.000Z",
"externalReference": "pedido-12345",
"e2eId": "E18189547202603160145ZYFfVx3jP8D"
}
}
| Campo | Tipo | Descrição |
|---|---|---|
blockId | string | ID único do bloqueio |
transactionId | string | ID da transação original bloqueada |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor bloqueado em reais |
currency | string | Moeda (BRL) |
blockType | string | Tipo do bloqueio (med, judicial ou administrative) |
referenceNumber | string | Número de referência do bloqueio |
reason | string | Motivo do bloqueio |
status | string | Status inicial (awaiting_response) |
createdAt | string | Data/hora da criação em ISO 8601 |
externalReference | string | Referência externa da transação original (opcional) |
e2eId | string | ID fim-a-fim da rede PIX da transação original (opcional) |
balance_block_approved
Enviado quando um bloqueio de saldo é aprovado e o valor é devolvido ao pagador original.{
"event": "balance_block_approved",
"eventId": "d4e5f6a7-8b9c-0d1e-2f3a-456789abcdef",
"timestamp": "2026-01-12T14:00:00.000Z",
"data": {
"blockId": "d4e5f6a7-8b9c-0d1e-2f3a-456789abcdef",
"transactionId": "a0b78f10-c7f4-4f5d-98dd-3e36eafeb812",
"environment": "production",
"amount": 1500.00,
"currency": "BRL",
"blockType": "med",
"referenceNumber": "MED-2026-001234",
"reason": "Notificação de infração Pix recebida",
"resolutionReason": "Devolução confirmada pelo BACEN",
"status": "approved",
"createdAt": "2026-01-11T19:30:00.000Z",
"resolvedAt": "2026-01-12T14:00:00.000Z",
"externalReference": "pedido-12345",
"e2eId": "E18189547202603160145ZYFfVx3jP8D"
}
}
| Campo | Tipo | Descrição |
|---|---|---|
blockId | string | ID único do bloqueio |
transactionId | string | ID da transação original bloqueada |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor bloqueado em reais |
currency | string | Moeda (BRL) |
blockType | string | Tipo do bloqueio (med, judicial ou administrative) |
referenceNumber | string | Número de referência do bloqueio |
reason | string | Motivo original do bloqueio |
resolutionReason | string | Motivo da resolução (opcional) |
status | string | Status do bloqueio (approved) |
createdAt | string | Data/hora da criação em ISO 8601 |
resolvedAt | string | Data/hora da resolução em ISO 8601 |
externalReference | string | Referência externa da transação original (opcional) |
e2eId | string | ID fim-a-fim da rede PIX da transação original (opcional) |
balance_block_rejected
Enviado quando um bloqueio de saldo é rejeitado e o valor retorna ao saldo disponível do lojista.{
"event": "balance_block_rejected",
"eventId": "e5f6a7b8-9c0d-1e2f-3a4b-567890abcdef",
"timestamp": "2026-01-12T14:00:00.000Z",
"data": {
"blockId": "e5f6a7b8-9c0d-1e2f-3a4b-567890abcdef",
"transactionId": "b1c89f20-d8e5-5f6a-99ee-4f47eafeb923",
"environment": "production",
"amount": 250.00,
"currency": "BRL",
"blockType": "med",
"referenceNumber": "MED-2026-005678",
"reason": "Notificação de infração Pix recebida",
"resolutionReason": "Defesa aceita - transação legítima comprovada",
"status": "rejected",
"createdAt": "2026-01-11T19:30:00.000Z",
"resolvedAt": "2026-01-12T14:00:00.000Z",
"externalReference": "pedido-67890",
"e2eId": "E4071059520260316020613919677838"
}
}
| Campo | Tipo | Descrição |
|---|---|---|
blockId | string | ID único do bloqueio |
transactionId | string | ID da transação original bloqueada |
environment | string | Ambiente (production ou sandbox) |
amount | number | Valor bloqueado em reais |
currency | string | Moeda (BRL) |
blockType | string | Tipo do bloqueio (med, judicial ou administrative) |
referenceNumber | string | Número de referência do bloqueio |
reason | string | Motivo original do bloqueio |
resolutionReason | string | Motivo da resolução (opcional) |
status | string | Status do bloqueio (rejected) |
createdAt | string | Data/hora da criação em ISO 8601 |
resolvedAt | string | Data/hora da resolução em ISO 8601 |
externalReference | string | Referência externa da transação original (opcional) |
e2eId | string | ID fim-a-fim da rede PIX da transação original (opcional) |
Boas Práticas
Responda rapidamente
Responda rapidamente
Retorne um status
200 OK o mais rápido possível. Processe o webhook de forma assíncrona se necessário.Implemente idempotência
Implemente idempotência
Use o
eventId para evitar processar o mesmo evento duas vezes. Webhooks podem ser reenviados em caso de falha.Use HTTPS
Use HTTPS
Configure seu endpoint apenas com HTTPS para garantir a segurança dos dados.
Retentativas
Se o seu endpoint não responder com status2xx, tentaremos reenviar o webhook:
- 5 tentativas com backoff exponencial
- Intervalo inicial: 2 segundos
- Intervalo máximo: ~30 segundos entre tentativas

