Handle overpayments
The Payments v.3 API endpoints are in beta and may change as we enhance the product. For the concepts this guide builds on, see Payments API v.3.
Overpayments occur when customers send more cryptocurrency than intended. For example, they intend to send 0.13275995 ETH but send 0.145 ETH instead. In this case, the payin still transitions to a COMPLETED status, and BVNK adds "OVER" to its labels[] array so you can tell it apart from an exact payment.
How can I see the actual amount received?
To see the actual received amount, on the payment:v3:payin:status-change webhook, or on a GET /payment/v3/payins/{id} response, compare the fields on originator:
originator.actual: the currency and amount the customer actually sent.originator.required: the currency and amount BVNK originally asked for.
required always means what was asked for, and actual always means what was paid.
{
"id": "7C41D2E8-9B03-4A17-8E52-1D6F3A0B7C94",
"reference": "myUniqueRef334",
"type": "payment:payin",
"direction": "IN",
"status": "COMPLETED",
"method": "CRYPTO",
"fees": {
"customerFee": null,
"processingFee": { "estimated": { "currency": "EUR", "amount": "1.12" }, "actual": { "currency": "EUR", "amount": "1.12" } },
"networkFee": null
},
"originator": {
"required": { "currency": "ETH", "amount": "0.13275995" },
"actual": { "currency": "ETH", "amount": "0.14500000" },
"customerId": "d063635e-0f83-4e47-a1f3-fc9484df1509",
"customerReference": null,
"requesterIpAddress": "172.16.254.1",
"entity": {
"type": "COMPANY",
"legalName": "BVNK LTD",
"registrationNumber": "5493001KJTIIGC8Y1R12",
"relationshipType": "SELF_OWNED",
"address": { "country": "GB" }
},
"paymentInstrument": {
"type": "CRYPTO_ADDRESS",
"network": "ETHEREUM",
"addresses": ["0x3f5ce5fbfe3e9af3971dd833d26ba9b5c936f0be"],
"tag": null
}
},
"beneficiary": {
"required": { "currency": "EUR", "amount": "223.05" },
"actual": { "currency": "EUR", "amount": "223.05" },
"walletId": "a:24092328494070:G5i4XZ9:1"
},
"conversion": {
"type": "QUOTE",
"baseRate": "1688.54",
"allInRate": "1680.1",
"spread": { "percentage": "0.005", "amount": "1.12", "currency": "EUR" },
"validityDuration": "PT60M",
"expiresAt": "2026-03-14T21:45:30Z"
},
"instructions": [
{
"type": "CRYPTO",
"network": "ETHEREUM",
"currency": "ETH",
"amount": "0.13275995",
"address": "0xc71e04b9a2f6d35081e7b40c9d2a68f5137e0b94",
"tag": null,
"uri": "ethereum:0xc71e04b9a2f6d35081e7b40c9d2a68f5137e0b94?value=1.3276e17"
}
],
"checkout": {
"required": { "currency": "EUR", "amount": "223.05" },
"actual": { "currency": "EUR", "amount": "243.61" },
"displayRate": { "from": "ETH", "to": "EUR", "rate": "1680.1" },
"redirectUrl": "https://pay.bvnk.com/payin/7C41D2E8-9B03-4A17-8E52-1D6F3A0B7C94",
"returnUrl": "https://my-shop.com/payment-complete?ref=xyz"
},
"trackingDetails": [
{
"amount": "0.14500000",
"currency": "ETH",
"hash": "0x3b7f19e5c204a86d0f13b7e29a4c85d073e1f6b092d4a7c58e0b3f6d1a9c4e70",
"network": "ETHEREUM",
"createdAt": "2026-03-14T20:51:18Z",
"confirmedAt": "2026-03-14T20:52:41Z"
}
],
"labels": ["OVER"],
"relatedPayments": [
{ "type": "payment:payout", "paymentId": "d4f81c66-3a29-4b7e-9c05-8e2f1a7b6d30" }
],
"statusHistory": [
{ "status": "PENDING_CUSTOMER_PAYMENT", "timestamp": "2026-03-14T20:45:30Z" },
{ "status": "PROCESSING", "timestamp": "2026-03-14T20:51:18Z" },
{ "status": "COMPLETED", "timestamp": "2026-03-14T20:52:41Z" }
],
"metadata": {},
"expiryDuration": "PT20M",
"expiresAt": "2026-03-14T21:05:30Z",
"updatedAt": "2026-03-14T20:52:41Z",
"createdAt": "2026-03-14T20:45:30Z"
}
BVNK asked for 0.13275995 ETH, worth 223.05 EUR at the quoted rate, but the customer sent 0.145 ETH, worth 243.61 EUR. The merchant's wallet is credited with the required 223.05 EUR, the payin is tagged labels: ["OVER"], and relatedPayments[] links forward to the payout created for the excess 0.01224005 ETH (d4f81c66-3a29-4b7e-9c05-8e2f1a7b6d30). See Refund payments for that payout in full.
Handle overpayments
To ensure the best customer experience when managing overpayments, it is advisable to adjust the final payment made by the customer to reflect the higher total amount received. This method eliminates the need to return minor excess amounts of cryptocurrency. Instead, the complete sum will be credited to the customer's account. There is the Settle Merchant Wallet setting, where the total sent amount is deposited into the MID wallet associated with the transaction.
The sent amount is indicated in the originator.actual object, which can then be referenced to update the customer's total payment amount in your system, in relation to the requested originator.required object.
In certain circumstances, such as regulatory issues that may arise when receiving more crypto than requested, the following alternative options can be used:
-
Handle manually: will retain the excess fraction of the transaction in its original cryptocurrency and deposit it into an equivalent cryptocurrency wallet on your account. The original payment amount is sent to the MID-linked wallet. You can then use the payout functionality to manually return the excess amount to the customer if required.
Example: the customer must pay 223.05 EUR and sends 0.145 ETH (243.61 EUR) instead of the required 0.13275995 ETH. You decide to handle the overpayment manually: settle 223.05 EUR to the MID wallet, and keep the excess 0.01224005 ETH in the cryptocurrency wallet.
-
Auto refund: will send the original payment amount to the MID-linked wallet. Any additional amount will be kept separately and attributed to a new payout, labelled
REFUND, withrelatedPayments[]linking it back to the overpaid payin. This payout resolves to a unique URL. This URL must be sent to the customer for final confirmation of the address where the excess funds should be sent.Example: the customer must pay 223.05 EUR but sends 0.145 ETH (243.61 EUR) instead of the required 0.13275995 ETH. You decide to settle 223.05 EUR to the MID wallet and refund the rest. The excess 0.01224005 ETH is kept separately, and BVNK creates a payout carrying
labels: ["REFUND"]. The link to claim it remains active for three months (expiryDuration: "P3M"). If the customer doesn't claim the funds within this period, the funds are settled into the merchant's account. -
Upper threshold: you can also set an upper threshold to define an acceptable overpayment variance margin. When it is active, any overpayment that falls within your specified buffer is treated as an exact payment: the payin completes with no
OVERlabel at all, overriding any Auto Refund or Handle manually configurations. If an overpayment exceeds this allowed threshold, the buffer is completely disregarded. In this case, the system reverts to your standard overpayment settings, and the payin completes withlabels: ["OVER"]to handle or refund the full excess amount received.Reach out to your account manager to enable this feature.Example: the customer must pay 100 USDT, overpayment refunds are enabled, and the upper threshold is set to 10 USDT. If the customer pays 105 USDT, the payin completes with an empty
labels[], because the overpayment falls within the accepted threshold buffer. If the customer pays 115 USDT instead, the overpayment exceeds the threshold margin: the payin completes withlabels: ["OVER"], and the system triggers your default overpayment configuration, generating an automatic refund payout for the full excess amount of 15 USDT.
Overpayment exception flows
The summary of the flow for four different outcomes is given below:
| Configuration | Balance impact | Payin status | Labels |
|---|---|---|---|
| Settle Merchant Wallet | Full amount of the overpayment is credited to your MID wallet in your wallet currency. For more information on a MID wallet, refer to the merchant setup guide. | COMPLETED | ["OVER"] |
| Handle Manually | The original payment amount is credited to your MID wallet in the currency of your wallet. The excess amount of cryptocurrency received is credited to the cryptocurrency wallet in the currency of the payment. | COMPLETED | ["OVER"] |
| Auto Refund | Functions similarly to Handle Manually, except it is done automatically for you. The original payment amount is credited to your MID wallet in the currency of your wallet. The excess amount of cryptocurrency received is attributed to a new refund payout, auto-created and linked back via relatedPayments[]. | Payin COMPLETED; refund payout PENDING_VERIFICATION | Payin ["OVER"]; payout ["REFUND"] |
| Upper Threshold | The full received amount is automatically accepted and credited to your MID wallet if it falls within your defined buffer, overriding standard overpayment configurations. | COMPLETED | [] (no exception recorded) |
The diagram below follows the example payin through each configuration:
Each payin status change sends a payment:v3:payin:status-change webhook. The refund payout sends its own payment:v3:payout:status-change webhooks.
To change your configuration or learn more, contact your Account or Integration Manager.