Refund Payments
Refunding payments automatically after a payment exception scenario occurs
In the case where a payment exception scenario has taken place, Layer1 provides the option to automatically refund the cryptocurrency for merchants who do not want to hold these cryptocurrencies, due to any compliance issues, or for merchants that do not want to internally process any payments that have fallen outside of the agreed upon payment rules.
An Auto Refund does not automatically return the funds to the sender's address. Instead, it automatically generates a payout and sends a URL via webhook. This URL should be forwarded to the end user, allowing them to provide their address and accept the refund.
How a refund works
Refunds function as an automatically generated payout request, which needs to be sent to the end user to complete. In this case, the end user will need to enter their desired wallet address that they want the funds to be sent to, and for them to confirm the payout.
Refunding payment exception scenarios
As stated on the previous pages, the three payment exception scenarios to consider are:
- Over payments
- Under payments
- Late payments
These three scenarios are handled separately on a Merchant ID (MID) level. Which means that each MID that is created can be set up to automatically initiate the refund process for one or more of these scenarios. Each Scenario handles the refund slightly differently, as explained below.
Please contact Merchant Support or your Integration Manager to have the refund options enabled.
Refunding over payments
When an over payment has occurred, the status of the transaction is updated from PROCESSING
to COMPLETE
. This COMPLETE
status should be seen as a standard successful payment on the merchant's side.
The original payment amount requested in the invoice is credited to the merchant's wallet as normal, but the additional amount of overpaid cryptocurrency goes into a holding account so that there is no impact on a merchant wallet balance.
This additional amount is then the total amount that will be returned back to the sender as an automatically generated payout.
Refunding under payments
When an under payment has occurred, the status of the transaction is updated from PROCESSING
to UNDERPAID
. This UNDERPAID
status should be marked as an unsuccessful payment on the merchant's side.
The entire payment amount is put into a holding account, so that it is not credited to the merchant's wallet.
The full payment amount of the underpayment is then the total amount that will be returned back to the sender as an automatically generated payout.
Refunding late payments
In the rare occurrence that a late payment has occurred, the status of the transaction is updated from PENDING
to EXPIRED
. This EXPIRED
status should be marked as an unsuccessful payment on the merchant's side.
The entire payment amount is put into a holding account, so that it is not credited to the merchant's wallet.
The full payment amount of the late payment is then the total amount that will be returned back to the sender as an automatically generated payout.
The refund flow
The ideal flow of an automatically generated refund is given as follows:
- The payment request is created for an end user by the merchant.
- The payment link returned from BVNK is forwarded to the end user by the merchant.
- The end user completes the payment by sending through funds to the given address.
- The total funds are either too low, too high, or received late, triggering the appropriate refund.
- The merchant is sent a webhook from BVNK, telling them the amount to refund and the URL that it can be claimed from.
- The merchant notifies the end user of 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.
Expiring a refund
In the event that the end user never entered their wallet address and confirms the refund within the expiry limit, the refund will become EXPIRED
. The default expiry limit for a refund is set to 3 months.
When the limit is reached, the total amount of the refund will move from the held account into the merchants MID wallet.
A further webhook will be sent to the merchant to indicate that the refund has expired and the amounts have been credited to the appropriate wallet.
Refund webhooks
BVNK will automatically initiate the refund process, which in effect acts as a payout transaction.
The merchant will receive a refundInitiated
event webhook. The appropriate important fields to pay attention to in this webhook are:
Webhook field | Description |
---|---|
event: refundIntiated | Will indicate that the refund has been intiated. |
data.uuid: xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx | The UUID of the refund, different to the linked payment in. |
data.type: OUT | The type of a refund will always be OUT |
data.subType: merchantRefund | The subtype indicated it is a Merchant Refund |
data.status: PENDING | The status of a refund, can become EXPIRED or COMPLETE |
data.redirectUrl: https://pay.bvnk.com/payout?uuid= | The redirect URL to send to the end user so they can enter their address and claim the refund. |
In the even that the refund is not claimed and has expired, a statusChanged
event webhook is sent to the merchant. The important fields in this webhook are:
Webhook field | Description |
---|---|
event: statusChanged | Will indicate that the refund has had its status changed. |
data.uuid: xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx | The matching UUID of the refund.. |
data.subType: merchantRefund | The subtype indicated it is a Merchant Refund |
data.status: EXPIRED | The final state of the expired payment |
Webhook Examples:
{
"source": "payment",
"event": "refundInitiated",
"data": {
"uuid": "9485895b-c4a3-4885-bcdc-XXXXXXXXXX",
"merchantDisplayName": "Merchant Name",
"merchantId": "00a4af9d-ad4b-42d5-bec4-XXXXXXXXXX",
"dateCreated": 1689264437804,
"expiryDate": 1689869237804,
"quoteExpiryDate": null,
"acceptanceExpiryDate": null,
"quoteStatus": "TEMPLATE",
"reference": "REFUND-XXXXX",
"type": "OUT",
"subType": "merchantRefund",
"status": "PENDING",
"displayCurrency": {
"currency": "EUR",
"amount": 24.58,
"actual": 0
},
"walletCurrency": {
"currency": "ETH",
"amount": 0.01421,
"actual": 0
},
"paidCurrency": {
"currency": null,
"amount": 0,
"actual": 0
},
"feeCurrency": {
"currency": "EUR",
"amount": 0.49,
"actual": 0.49
},
"displayRate": null,
"exchangeRate": null,
"address": null,
"returnUrl": "",
"redirectUrl": "https://pay.sandbox.bvnk.com/payout?uuid=9485895b-c4a3-4885-bcdc-XXXXXXXXXX",
"transactions": [],
"refund": {
"uuid": "309d82fd-e1d4-4354-9015-XXXXXXXXXX",
"merchantDisplayName": "Merchant Name",
"merchantId": "00a4af9d-ad4b-42d5-bec4-XXXXXXXXXX",
"dateCreated": 1689264326000,
"expiryDate": 1689265526000,
"quoteExpiryDate": 1689265526000,
"acceptanceExpiryDate": 1689264363000,
"quoteStatus": "ACCEPTED",
"reference": "reference",
"type": "IN",
"subType": "merchantPayIn",
"status": "COMPLETE",
"displayCurrency": {
"currency": "EUR",
"amount": 10,
"actual": 10
},
"walletCurrency": {
"currency": "EUR",
"amount": 10,
"actual": 10
},
"paidCurrency": {
"currency": "ETH",
"amount": 0.00579,
"actual": 0.02
},
"feeCurrency": {
"currency": "EUR",
"amount": 0.1,
"actual": 0.1
},
"displayRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1727.070973981676
},
"exchangeRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1727.071668
},
"address": {
"address": "0x434c932fc5e324204c80c1fb15f3a7XXXXX",
"tag": null,
"protocol": "ETH",
"uri": "ethereum:0x434c932fc5e324204c80c1fb15f3a7XXXXX?value=5.79015E+15",
"alternatives": []
},
"returnUrl": "",
"redirectUrl": "https://pay.sandbox.bvnk.com/payin?uuid=309d82fd-e1d4-4354-9015-XXXXXXXXXX",
"transactions": [
{
"dateCreated": 1689264367000,
"dateConfirmed": 1689264429000,
"hash": "0x034612080ab226a5c3254b521f30dafd7df30dd1c1fc35723cf6XXXXX",
"amount": 0.02,
"risk": {
"level": "LOW",
"resourceName": "UNKNOWN",
"resourceCategory": "UNKNOWN",
"alerts": []
},
"networkFeeCurrency": "ETH",
"networkFeeAmount": 0.0000315,
"sources": [
"0x4b8b57aa7a92ea959c92aa32a72bbXXXXX3"
],
"displayRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1727.070973981676
},
"exchangeRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1727.071668
}
}
],
"refund": null,
"refunds": []
},
"refunds": []
}
}
{
"source": "payment",
"event": "statusChanged",
"data": {
"uuid": "9485895b-c4a3-4885-bcdc-XXXXXXXXXX",
"merchantDisplayName": "Merchant Name",
"merchantId": "00a4af9d-ad4b-42d5-bec4-XXXXXXXXXX",
"dateCreated": 1689264438000,
"expiryDate": 1689264510403,
"quoteExpiryDate": 1689275310395,
"acceptanceExpiryDate": 1689264540395,
"quoteStatus": "ACCEPTED",
"reference": "REFUND-XXXXX",
"type": "OUT",
"subType": "merchantRefund",
"status": "EXPIRED",
"displayCurrency": {
"currency": "EUR",
"amount": 24.58,
"actual": 0
},
"walletCurrency": {
"currency": "EUR",
"amount": 23.49968,
"actual": 23.49968
},
"paidCurrency": {
"currency": null,
"amount": 0,
"actual": 0
},
"feeCurrency": {
"currency": "EUR",
"amount": 0.49,
"actual": 0.49
},
"displayRate": null,
"exchangeRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1653.7602177875
},
"address": null,
"returnUrl": "",
"redirectUrl": "https://pay.sandbox.bvnk.com/payout?uuid=9485895b-c4a3-4885-bcdc-XXXXXXXXXX",
"transactions": [],
"refund": {
"uuid": "309d82fd-e1d4-4354-9015-XXXXXXXXXX",
"merchantDisplayName": "Metallica Inc",
"merchantId": "00a4af9d-ad4b-42d5-bec4-XXXXXXXXXX",
"dateCreated": 1689264326000,
"expiryDate": 1689265526000,
"quoteExpiryDate": null,
"acceptanceExpiryDate": null,
"quoteStatus": "TEMPLATE",
"reference": "XXXXXXXXXX",
"type": "IN",
"subType": "merchantPayIn",
"status": "COMPLETE",
"displayCurrency": {
"currency": "EUR",
"amount": 10,
"actual": 10
},
"walletCurrency": {
"currency": "EUR",
"amount": 10,
"actual": 10
},
"paidCurrency": {
"currency": "ETH",
"amount": 0.00579,
"actual": 0.02
},
"feeCurrency": {
"currency": "EUR",
"amount": 0.1,
"actual": 0.1
},
"displayRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1727.070973981676
},
"exchangeRate": null,
"address": null,
"returnUrl": "",
"redirectUrl": "https://pay.sandbox.bvnk.com/payin?uuid=309d82fd-e1d4-4354-9015-XXXXXXXXXX",
"transactions": [
{
"dateCreated": 1689264367000,
"dateConfirmed": 1689264429000,
"hash": "0x034612080ab226a5c3254b521f30dafd7df30dd1c1fc35723cf638XXXXX",
"amount": 0.02,
"risk": {
"level": "LOW",
"resourceName": "UNKNOWN",
"resourceCategory": "UNKNOWN",
"alerts": []
},
"networkFeeCurrency": "ETH",
"networkFeeAmount": 0.0000315,
"sources": [
"0x4b8b57aa7a92ea959c92aa32a72bb3dXXXXX7"
],
"displayRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1727.070973981676
},
"exchangeRate": {
"base": "ETH",
"counter": "EUR",
"rate": 1727.071668
}
}
],
"refund": null,
"refunds": []
},
"refunds": []
}
}
Updated 2 months ago