Recursos
Webhooks
Notificações em tempo real quando algo acontece. Realfy envia POST pro seu endpoint sempre que um pagamento muda de status, com assinatura HMAC pra você verificar autenticidade.
Setup
- Painel → Webhooks → Novo endpoint
- Informa a URL HTTPS pública do seu sistema (ex:
https://app.com/webhooks/realfy) - Copia o
secretgerado e guarda no env do seu app - Pronto — eventos novos já começam a ser entregues
Eventos disponíveis
| Evento | Quando dispara |
|---|---|
deposit.created | Cobrança PIX criada (QR Code disponível) |
deposit.paid | Cobrança paga — saldo já caiu na sua conta |
deposit.expired | QR Code expirou sem pagamento |
withdrawal.created | Saque PIX criado, aguardando processamento |
withdrawal.processing | Provedor BaaS começou a processar |
withdrawal.completed | PIX entregue no destinatário |
withdrawal.failed | PIX falhou — saldo já estornado |
Formato do payload
POST https://seu-site.com/webhooks/realfy
X-Realfy-Signature: t=1779800000,v1=5257a869e7ecebeda...
X-Realfy-Event: deposit.paid
X-Realfy-Delivery-Id: del_xyz123
Content-Type: application/json
{
"event": "deposit.paid",
"data": {
"id": "dep_4054",
"amount": 50.00,
"netAmount": 49.25,
"status": "paid",
"reference": "order-001",
"createdAt": "2026-05-26T13:30:00Z",
"paidAt": "2026-05-26T13:31:42Z"
}
} Verificar a assinatura
✕
Sempre verifique a assinatura
Sem verificar, qualquer um pode forjar requests fingindo ser de Realfy e marcar pedidos
como pagos no seu sistema. Nunca processe o evento sem validar primeiro.
A assinatura usa HMAC-SHA256 do timestamp + body, com o secret do endpoint. Pseudocódigo:
expected = HMAC-SHA256(secret, "${timestamp}.${rawBody}").hex()
if (expected !== signatureHeader.v1) → rejeite
if (now - timestamp > 5min) → rejeite (replay attack) Implementação na sua linguagem:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhook(rawBody, signatureHeader, secret) {
// Parse header "t=1779800000,v1=abc123..."
const parts = Object.fromEntries(
signatureHeader.split(',').map((p) => p.split('='))
);
// 1. Reconstrói o HMAC esperado
const signedPayload = `${parts.t}.${rawBody}`;
const expected = createHmac('sha256', secret).update(signedPayload).digest('hex');
// 2. Compara em tempo constante (evita timing attack)
const expectedBuf = Buffer.from(expected, 'hex');
const receivedBuf = Buffer.from(parts.v1, 'hex');
if (expectedBuf.length !== receivedBuf.length) {
throw new Error('Invalid signature');
}
if (!timingSafeEqual(expectedBuf, receivedBuf)) {
throw new Error('Invalid signature');
}
// 3. Verifica janela de 5min (anti-replay)
const timestampMs = Number(parts.t) * 1000;
if (Date.now() - timestampMs > 5 * 60 * 1000) {
throw new Error('Webhook expired (replay attack?)');
}
}
// No Express:
app.post('/webhooks/realfy', express.raw({ type: 'application/json' }), (req, res) => {
try {
verifyWebhook(
req.body.toString(),
req.headers['x-realfy-signature'],
process.env.WEBHOOK_SECRET
);
} catch (err) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString());
console.log('Webhook validated:', event.event, event.data);
res.status(200).send('OK');
}); ⚠
Use o raw body
A assinatura é calculada sobre o body cru (bytes), antes de qualquer parsing JSON.
Se você der
JSON.parse e depois re-stringificar, a ordem dos campos pode mudar e a
assinatura falha. Sempre intercepta o body raw (Express: express.raw(), Fastify:
contentTypeParser).
Retry policy
Se seu endpoint retornar não-2xx ou timeout (5s), reenviamos automaticamente:
| Tentativa | Delay desde criação |
|---|---|
| 1ª (inicial) | imediato |
| 2ª | +1 min |
| 3ª | +5 min |
| 4ª | +30 min |
| 5ª (final) | +1 h |
Após 5 tentativas, o delivery vira failed e você pode reenviar manualmente pelo painel.
Boas práticas
- Responda rápido — 2xx em < 1s. Se precisar processar, enfileira um job no seu lado.
- Seja idempotente — o mesmo evento pode chegar 2x (retry após network flap). Use
X-Realfy-Delivery-Idcomo dedup. - Loga tudo — guarde o body e a assinatura recebida pra investigar disputas.
- HTTPS sempre — não aceitamos URLs HTTP.