Se um pagamento for criado com webhookUrl, a API enviará notificações HTTP (webhooks) para os seguintes eventos:
payment.created — enviado após a criação do pagamento
payment.status_changed — enviado quando o status do pagamento muda
Assinatura digital de webhooks
Todos os webhooks enviados pela API pública são assinados digitalmente para garantir:
- Autenticidade (o webhook foi realmente enviado pela Paguebit)
- Integridade (o payload não foi alterado)
- Proteção contra replay attacks
Cada webhook inclui os seguintes headers HTTP:
| Header | Descrição |
|---|
X-Paguebit-Signature | Assinatura HMAC-SHA256 do payload |
X-Paguebit-Timestamp | Timestamp Unix (segundos) |
X-Paguebit-Event-Id | ID único do evento |
Observação: headers HTTP são case-insensitive.
X-Paguebit-Signature e x-paguebit-signature são equivalentes.
Como funciona a assinatura
Ao criar um token de API pública, você recebe um webhookSecret exclusivo.
A cada webhook enviado, a API:
-
Obtém o corpo bruto (raw body) da requisição
-
Concatena o timestamp no formato:
-
Gera uma assinatura usando HMAC-SHA256
-
Envia o resultado no header
X-Paguebit-Signature (hexadecimal)
signed_payload = "{timestamp}.{rawBody}"
signature = HMAC_SHA256(webhookSecret, signed_payload)
Validando a assinatura
Para validar um webhook recebido:
-
Leia os headers:
X-Paguebit-Signature
X-Paguebit-Timestamp
-
Obtenha o corpo bruto da requisição
-
Gere a assinatura localmente usando o mesmo algoritmo
-
Compare as assinaturas usando comparação segura
Exemplo em Node.js (Express)
import crypto from 'crypto';
import express from 'express';
function validateWebhookSignature(
rawBody: string,
timestamp: string,
signature: string,
webhookSecret: string,
): boolean {
const signedPayload = `${timestamp}.${rawBody}`;
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex'),
);
}
const app = express();
app.post(
'/webhook',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-paguebit-signature'] as string;
const timestamp = req.headers['x-paguebit-timestamp'] as string;
const rawBody = req.body.toString('utf8');
if (!signature || !timestamp) {
return res.status(400).send('Missing webhook headers');
}
const isValid = validateWebhookSignature(
rawBody,
timestamp,
signature,
process.env.WEBHOOK_SECRET!,
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const payload = JSON.parse(rawBody);
console.log('Webhook válido:', payload);
res.status(200).send('OK');
},
);
A validação deve ser feita antes de qualquer processamento do payload.
O rawBody deve ser usado exatamente como recebido.
Não faça JSON.parse + JSON.stringify antes de validar, pois isso altera o conteúdo e invalida a assinatura.
Payload do webhook
Campos enviados em todos os eventos:
| Campo | Tipo | Descrição |
|---|
event | string | Tipo do evento |
id | string | ID do pagamento |
status | string | Status atual |
amount | number | Valor do pagamento (BRL) |
storeId | string | ID da loja |
createdAt | string | Data ISO de criação |
email | string | E-mail do pagamento |
observation | string? | Observação |
qrCodeUrl | string? | URL do QR Code |
qrCopyPaste | string? | QR Copia e Cola |
isPublic | boolean | Indica se o pagamento é público |
Campo adicional em payment.status_changed
| Campo | Tipo | Descrição |
|---|
previousStatus | string | Status anterior |
Exemplo — payment.created
{
"event": "payment.created",
"id": "pay_123",
"status": "pending",
"amount": 150,
"storeId": "store_abc",
"createdAt": "2025-12-16T15:00:00.000Z",
"observation": "Pedido #9876",
"email": "cliente@example.com",
"qrCodeUrl": "https://.../qrcode.png",
"qrCopyPaste": "000201010212...",
"isPublic": true
}
Exemplo — payment.status_changed
{
"event": "payment.status_changed",
"id": "pay_123",
"status": "approved",
"previousStatus": "pending",
"amount": 150,
"storeId": "store_abc",
"createdAt": "2025-12-16T15:00:00.000Z",
"observation": "Pedido #9876",
"email": "cliente@example.com",
"qrCodeUrl": "https://.../qrcode.png",
"qrCopyPaste": "000201010212...",
"isPublic": true
}
Testando webhooks
Ferramentas recomendadas:
Essas ferramentas permitem validar rapidamente a assinatura antes de ir para produção.
Resumo rápido
| Item | Valor |
|---|
| Algoritmo | HMAC-SHA256 |
| Header da assinatura | X-Paguebit-Signature |
| Header do timestamp | X-Paguebit-Timestamp |
| Payload assinado | {timestamp}.{rawBody} |
| Encoding | Hexadecimal |
| Proteção contra replay | ✅ |