Pular para o conteúdo principal

Quando dispara

O evento refund_in é disparado quando uma transação cash-out enviada por você é devolvida pela contraparte. O saldo correspondente é creditado de volta na sua conta. Cenários comuns:
  • Beneficiário rejeitou a transferência manualmente
  • CLABE existia mas conta foi encerrada após a confirmação inicial
  • Estorno solicitado pelo beneficiário dentro do prazo SPEI

Payload

{
  "event": "refund_in",
  "deliveryId": "5b9c2d8e-4f12-4a18-bb29-88a3b4c5d6f7",
  "createdAt": "2026-05-14T09:15:00.000Z",
  "transaction": {
    "id": 67890,
    "externalId": "payout-001-refund",
    "paymentMethod": "SPEI",
    "direction": "in",
    "type": "refund_in",
    "status": "CONFIRMED",
    "provider": "smartfastpay",
    "amountCentavos": 50000,
    "clabe": "012180001234567890",
    "createdAt": "2026-05-14T09:14:50.000Z",
    "confirmedAt": "2026-05-14T09:15:00.000Z"
  },
  "originalTransactionId": 56789
}
O campo originalTransactionId aponta para o id do cash-out original que foi estornado. Use para correlacionar.

Resposta Esperada

HTTP 200 OK em até 10 segundos.

Exemplos de Handler

import express from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.raw({ type: 'application/json' })); // raw body for HMAC

const SECRET = process.env.NTXPAY_WEBHOOK_SECRET!;

app.post('/webhooks/ntxpay', (req, res) => {
  const sig = req.header('X-NTXPay-Signature') ?? '';
  const expected = 'sha256=' + crypto
    .createHmac('sha256', SECRET)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).end();
  }

  const event = JSON.parse(req.body.toString());
  if (event.event === 'refund_in') {
    // Balance credit already happened automatically
    markPayoutAsRefunded({
      originalId: event.originalTransactionId,
      refundId: event.transaction.id,
      amount: event.transaction.amountCentavos,
    });
  }

  res.json({ received: true });
});