Refund Payments
When a payment exception occurs, BVNK offers automatic cryptocurrency refunds for partners who do not wish to hold these assets due to compliance concerns or who prefer not to process payments outside agreed payment rules.
This refund flow generates a payout link that must be forwarded to the end user, allowing them to provide their wallet address and accept the refund.
If you want funds returned directly to the sender's wallet address with no end-user action required, see Refund to source address.
How a refund works
Refunds are automatically generated payout requests that must be sent to the end user for completion. The user enters their preferred wallet address and confirms the payout.
Contact your Merchant Support or Integration Manager to enable the refund options.
Refund exception scenarios
There are three payment exception scenarios to consider:
- Overpayments
- Underpayments
- Late payments
Each scenario processes refunds differently, as explained below.
If you use walletID in the request that triggers the webhook, you will also receive this field in the webhook response. You can ignore merchantID, as it will be discontinued soon.
- Overpayments
- Underpayments
- Late payments
When an overpayment occurs, the transaction status updates from PROCESSING to COMPLETE. Treat this COMPLETE status as a standard successful payment.
The original invoice amount is credited to the merchant's wallet as usual. The excess overpaid amount is deposited into a holding account, ensuring the merchant's wallet balance is unaffected.
This additional amount is returned to the sender as an automatically generated payout.
Refund flow
The typical flow for an automatically generated refund is as follows:
- The merchant creates the payment request for an end user.
- The merchant forwards the payment link returned from BVNK to the end user.
- The end user completes the payment by sending funds to the given address.
- The total funds amount is too low, too high, or received late, triggering the appropriate refund.
- BVNK sends a webhook notification to the merchant, specifying the amount to refund and the URL where it can be claimed.
- The merchant notifies the end user about the URL.
- The end user navigates to the URL and enters their wallet address.
- Once BVNK receives this address, the displayed amount of cryptocurrency is sent through, less the fees.
- The merchant receives a relevant webhook that updates the success of the refund payout.
- The process is complete.
Expired refund
If the end user does not enter their wallet address and confirm the refund within the expiry limit:
- The refund status changes to
EXPIRED. The default expiry limit is three months. - When the limit is reached, the refund amount is transferred from the holding account to the merchant's MID wallet.
- A further webhook is sent to the merchant to indicate that the refund has expired and the amounts have been credited to the appropriate wallet.
Refund webhook
BVNK automatically initiates the refund process, which functions as a payout transaction.
You will receive a refundInitiated event webhook. Review the following webhook fields:
| Webhook field | Description |
|---|---|
event: refundIntiated | Event type indicating that the refund has been initiated. |
data.uuid: xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx | UUID of the refund, different to the linked incoming payment. |
data.type: OUT | Type. For a refund, it is always set to OUT. |
data.subType: merchantRefund | Subtype indicating it is a Merchant refund. |
data.status: PENDING | Status of a refund. Possible options: EXPIRED or COMPLETE. |
data.redirectUrl: https://pay.bvnk.com/payout?uuid= | URL to send to the end user, allowing them to enter their address and claim the refund. |
If the refund is not claimed and expires, a statusChanged event webhook is sent to the merchant. The key fields in this webhook are:
| Webhook field | Description |
|---|---|
event: statusChanged | Event type indicating that the refund has had its status changed. |
data.uuid: xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx | Matching UUID of the refund. |
data.subType: merchantRefund | Subtype indicating it is a Merchant refund. |
data.status: EXPIRED | Final state of the expired payment. |
For more details, see the Refund webhook reference.
Auto-refund to source address
Auto-refund to source address enables eligible transactions to be automatically refunded directly to the originating source address. This eliminates the need for refund links that end users must open and claim, helping resolve LATE, OVERPAID, or UNDERPAID payments more quickly.
Enable auto-refund to source address
Contact your Account Manager to enable this feature. It can be configured per wallet and activated for any combination of exception types:
How it works
When auto-refund to source address is enabled and a payment exception occurs, funds are sent back to the blockchain address that originated the payment.
The process depends on the type of wallet used by the end user:
| Wallet type | Behaviour |
|---|---|
| Self-hosted wallet | Funds immediately appear back in the end user's original wallet. No further action is needed. |
| Centralised exchange (CEX) | The refund is sent to the exchange's pooled account. The end user must submit the transaction hash to their exchange to have the funds credited to their account. |
Supported currencies
Auto-refund to source address is supported for the following currencies:
- ETH
- USDT
- USDC
- BNB
- PYUSD
- XRP
- SOL
- POL
- TRX
Bitcoin uses a UTXO-based model where transactions can have multiple inputs, making the source address ambiguous. For BTC payments, the standard refund process (refund link) still applies.
For unsupported currencies, the standard refund link flow described above applies.
Webhook notifications
When a payment exception occurs and auto-refund to source address is enabled, you receive webhook notifications for both the exception event and the refund event.
Late payment webhook:
{
"event": "statusChanged",
"data": {
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "EXPIRED",
"type": "IN",
"subType": "merchantPayIn"
}
}
Auto-refund initiated webhook:
{
"event": "refundInitiated",
"data": {
"uuid": "f9e8d7c6-b5a4-3210-fedc-ba0987654321",
"type": "OUT",
"subType": "merchantRefund",
"status": "PROCESSING"
}
}
When the refund completes, a statusChanged webhook is sent with "status": "COMPLETE".