Webhook events
INFI uses canonical, stable event names. The name is delivered in the X-Infi-Event header and in the body’s event field, always in the same format (lowercase, dot-separated).
The event names listed below are stable across versions. You can compare directly: if (req.headers['x-infi-event'] === 'transaction.paid') { ... }. No normalization needed.
PIX charges (type: "transaction")
Events of the lifecycle of an incoming charge.
| Event | When it occurs |
|---|---|
transaction.paid | Payment confirmed and credited to balance. |
transaction.failed | Payment failure (timeout, payer refusal). |
transaction.cancelled | Charge cancelled before payment. |
transaction.expired | Deadline expired with no payment. |
transaction.refunded | Full refund. Merchant balance debited. |
transaction.partially_refunded | Partial refund. |
transaction.infraction | MED (Special Refund Mechanism) opened — balance preventively blocked. |
transaction.dispute | Dispute opened by the payer. |
transaction.protest | Protest registered against the transaction. |
transaction.blocked | Funds blocked by court order or compliance. |
transaction.chargeback | Chargeback applied — balance permanently debited. |
PIX withdrawals (type: "transfer")
Events of the lifecycle of a transfer (withdrawal) initiated by your API key or via the dashboard.
| Event | When it occurs |
|---|---|
transfer.created | Withdrawal created, awaiting processing. |
transfer.processing | Withdrawal being processed at the bank. |
transfer.pending_approval | Withdrawal over the limit — awaits manual internal approval. |
transfer.approved | Withdrawal manually approved, moves to processing. |
transfer.rejected | Withdrawal manually rejected. Balance returned. |
transfer.paid | Withdrawal successfully completed. |
transfer.failed | Withdrawal failed (invalid PIX key, etc.). Balance returned. |
transfer.cancelled | Withdrawal cancelled before processing. Balance returned. |
transfer.refunded | Recipient returned the amount (PIX Reversal). Balance re-credited. |
transfer.partially_refunded | Recipient returned part of the amount. Balance re-credited proportionally. |
Headers on every POST
| Header | Description |
|---|---|
X-Infi-Event | Canonical event name (e.g., transaction.paid). |
X-Infi-Timestamp | Unix timestamp in seconds, part of the signature. |
X-Infi-Signature | sha256=<hex> — HMAC-SHA256 over ${timestamp}.${rawBody}. See Signature. |
X-Infi-Event-Id | Unique event ID (evt_<ts>_<rand>). Use for dedup across multiple URLs and manual resends. |
Optional fields (PIX)
For events where the payment was actually settled, the webhook carries PIX data from the SPI/BACEN network:
| Field | Where it appears | Content |
|---|---|---|
endToEndId | transaction.paid / transaction.refunded / transaction.partially_refunded / transfer.paid / transfer.refunded / transfer.partially_refunded | BACEN-standard E2E ID (format E<ISPB><YYYYMMDDhhmm><id>). Unique per PIX. |
payer | transaction.* (PIX in — who paid you) | Object with name, document, documentType and bankAccount. |
beneficiary | transfer.* (PIX out — who received your withdrawal) | Object with name, document, documentType and bankAccount. |
refundEndToEndId | transfer.refunded / transfer.partially_refunded only | E2E ID of the refund PIX (different from the endToEndId of the original PIX). |
Structure of payer and beneficiary:
{
"name": "Maria Santos",
"document": "98765432100",
"documentType": "cpf",
"bankAccount": {
"ispb": "18236120",
"branch": "1",
"account": "914453272"
}
}The payer.* and beneficiary.* fields contain personal data (name, CPF/CNPJ, bank account). Treat them as any personal data: store only what’s necessary, with restricted access, and respect the holder’s right to deletion. INFI delivers this data because it comes from the PIX network — you are the controller for subsequent processing.
Events that do not carry these fields: transaction.failed, transaction.cancelled, transaction.expired, transfer.created, transfer.processing, transfer.pending_approval, transfer.approved, transfer.rejected, transfer.failed, transfer.cancelled. The fields are omitted from the JSON when unavailable (not returned as null).
Example: transaction.paid
{
"event": "transaction.paid",
"eventId": "evt_1715000000000_abcdef12",
"transactionId": "Q4t9aV...",
"status": "paid",
"amountCents": 1000,
"feeCents": 8,
"netCents": 992,
"paidAt": "2026-05-08T03:30:00.000Z",
"timestamp": "1715000000",
"endToEndId": "E18236120202605080330abc123",
"payer": {
"name": "Maria Santos",
"document": "98765432100",
"documentType": "cpf",
"bankAccount": {
"ispb": "18236120",
"branch": "1",
"account": "914453272"
}
}
}Example: transaction.refunded
{
"event": "transaction.refunded",
"eventId": "evt_1715003600000_def456",
"transactionId": "Q4t9aV...",
"status": "refunded",
"amountCents": 1000,
"feeCents": 8,
"netCents": 992,
"paidAt": null,
"timestamp": "1715003600",
"endToEndId": "E18236120202605080330abc123",
"payer": {
"name": "Maria Santos",
"document": "98765432100",
"documentType": "cpf",
"bankAccount": {
"ispb": "18236120",
"branch": "1",
"account": "914453272"
}
}
}The refund amount (partial or full) is automatically debited from your INFI balance. No additional action needed.
transaction.partially_refundedhas the same schema.
Example: transfer.paid
{
"event": "transfer.paid",
"eventId": "evt_1715000300000_345678ab",
"transactionId": "...",
"status": "paid",
"amountCents": 5000,
"feeCents": 4,
"netCents": 4996,
"paidAt": "2026-05-08T03:35:00.000Z",
"timestamp": "1715000300",
"endToEndId": "E04838403202605080335ABCDEF",
"beneficiary": {
"name": "João Silva",
"document": "12345678901",
"documentType": "cpf",
"bankAccount": {
"ispb": "18236120",
"branch": "0001",
"account": "123456789"
}
}
}Example: transfer.refunded (withdrawal return)
{
"event": "transfer.refunded",
"eventId": "evt_1715004000000_999",
"transactionId": "...",
"status": "transfer_refunded",
"amountCents": 5000,
"feeCents": 4,
"netCents": 4996,
"paidAt": null,
"timestamp": "1715004000",
"endToEndId": "E04838403202605080335ABCDEF",
"refundEndToEndId": "D18236120202605080500abc789",
"beneficiary": {
"name": "João Silva",
"document": "12345678901",
"documentType": "cpf",
"bankAccount": {
"ispb": "18236120",
"branch": "0001",
"account": "123456789"
}
}
}When the recipient returns a PIX you sent, the balance is automatically re-credited.
transfer.partially_refundedhas the same schema withamountCentsequal to the partially returned amount.
Example: transfer.failed
{
"event": "transfer.failed",
"eventId": "evt_1715000600000_9abc1234",
"transactionId": "...",
"status": "failed",
"amountCents": 5000,
"feeCents": 4,
"netCents": 4996,
"paidAt": null,
"timestamp": "1715000600"
}For withdrawals ending in
failed,cancelledorrejected, the balance is automatically returned. No action on your side beyond marking the operation. These events do not carryendToEndIdorbeneficiary(no settlement happened).
Categories for multi-webhook
You can configure one URL per category or mix as you like using event filters. See Configuring for full setup.
| Category | Covered events |
|---|---|
cashin (payments) | transaction.paid, transaction.failed, transaction.cancelled, transaction.expired |
refund (refunds) | transaction.refunded, transaction.partially_refunded |
dispute (disputes / holds) | transaction.infraction, transaction.dispute, transaction.protest, transaction.blocked |
chargeback | transaction.chargeback |
cashout (withdrawals) | transfer.* (all 10 events) |