Two Step Crypto Payouts

The two step process allows you to initiate a crypto payout with detailed information (meaning including the destination wallet), where the payout must be accepted in two stages. This approach provides an additional layer of security and control before the funds are moved.

Step 1: Initiate the Payout Request

Create a payout request, providing details such as currency, amount, destination address, and any additional necessary details. Specify that this is a two step payout by including the following attribute twoStep: true.

POST /api/v1/pay/summary for full information about this endpoint please read through Creating a crypto payout.

{
    "merchantId": "86955f40-8f4e-464c-be2b-583635bf1c62",
    "type": "OUT",
    "amount": 10,
    "currency": "USD",
    "expiryMinutes": 30,
    "reference": "test_reference_out_v38yEy",
    "returnUrl": "https://your-url-here.com/status",
    "payOutDetails": {
        "code": "crypto",
        "currency": "USDT",
        "protocol": "ERC20",
        "address": "0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156",
        "tag": null
    },
    "customerId": "74cf81d7-632d-4d71-9565-fea24e4955db",
    "complianceDetails": {
        "requesterIpAddress": "77.71.188.87",
        "partyDetails": [
            {
                "type": "BENEFICIARY",
                "entityType": "INDIVIDUAL",
                "firstName": "John",
                "lastName": "Doe",
                "dateOfBirth": "1984-06-30",
                "relationshipType": "THIRD_PARTY",
                "countryCode": "DE"
            }
        ]
    }
}

You will get a 200 OK message and the response body:

{
    "uuid": "e7f5d20f-cf68-4c7a-86c2-1ad957bc1913",
    "merchantDisplayName": "Euro Company",
    "merchantId": "86955f40-8f4e-464c-be2b-583635bf1c62",
    "dateCreated": 1738759638604,
    "expiryDate": 1738761438604,
    "quoteExpiryDate": 1738761438604,
    "acceptanceExpiryDate": 1738759668830,
    "quoteStatus": "ACCEPTED",
    "reference": "test_reference_out_rJ8bXl",
    "type": "OUT",
    "subType": "merchantPayOut",
    "status": "PROCESSING",
    "displayCurrency": {
        "currency": "USD",
        "amount": 10,
        "actual": 0
    },
    "walletCurrency": {
        "currency": "EUR",
        "amount": 9.21,
        "actual": 9.21
    },
    "paidCurrency": {
        "currency": "USDT",
        "amount": 9.105526,
        "actual": 0
    },
    "feeCurrency": {
        "currency": "EUR",
        "amount": 0.09,
        "actual": 0
    },
    "networkFeeCurrency": {
        "currency": "USDT",
        "amount": 1.03584,
        "actual": 0
    },
    "displayRate": {
        "base": "USDT",
        "counter": "USD",
        "rate": 1.09823419317
    },
    "exchangeRate": {
        "base": "EUR",
        "counter": "USDT",
        "rate": 0.988656467895
    },
    "address": {
        "address": "0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156",
        "tag": null,
        "protocol": "ERC20",
        "uri": "ethereum:0xdac17f958d2ee523a2206206994597c13d831ec7/transfer?address=0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156&uint256=9105526",
        "alternatives": []
    },
    "returnUrl": "https://your-url-here.com/status",
    "redirectUrl": "https://pay.sandbox.bvnk.com/payout/e7f5d20f-cf68-4c7a-86c2-1ad957bc1913",
    "transactions": [],
    "refund": null,
    "refunds": [],
    "currencyOptions": [],
    "flow": "DEFAULT",
    "twoStep": false
}

Step 2: Process the Payout

As you can see from the response, once the payout is created, the quote will get ACCEPTED automatically immediately. Now you can review the quote and if you are happy, you could proceed with confirming the payout to move the funds.

⚠️ The quote is open for 1 hour. If you want to proceed with the payout you would need to hit our PUT /api/v1/pay/{{uuid}}/confirm/summary within this timeframe for us to move funds to the destination wallet. If you do not wish to move the funds, the quote will simply expire automatically after the 1 hour.

Below is an example of the request: PUT /api/v1/pay/{{uuid}}/confirm/summary . No payload body is required.

curl --location --request PUT '<https://api.sandbox.bvnk.com/api/v1/pay/e7f5d20f-cf68-4c7a-86c2-1ad957bc1913/confirm/summary'>  
--header 'Authorization: Hawk id="vbfc61D890wg6LAAVbkR11qP9O6cXeMNmKWgcUNZaOHPiQeebp9cl6h02tWv84R8", ts="1738759219", nonce="0EScmH", mac="KwsvII+jII14+vHdAKplxWYX5IBcb5uPd2Wt9RfCTyE="'

You will get a 200 OK message and the response body:

{
    "uuid": "954cc08a-d621-4fb3-b2a1-2f76507c8385",
    "merchantDisplayName": "Euro Company",
    "merchantId": "86955f40-8f4e-464c-be2b-583635bf1c62",
    "dateCreated": 1738759215000,
    "expiryDate": 1738761015000,
    "quoteExpiryDate": 1738761015000,
    "acceptanceExpiryDate": 1738759245000,
    "quoteStatus": "ACCEPTED",
    "reference": "0f6920ea-a955-476d-a70f-077b9c180dab",
    "type": "OUT",
    "subType": "merchantPayOut",
    "status": "PROCESSING",
    "displayCurrency": {
        "currency": "USD",
        "amount": 2.5,
        "actual": 0
    },
    "walletCurrency": {
        "currency": "EUR",
        "amount": 2.3,
        "actual": 2.3
    },
    "paidCurrency": {
        "currency": "USDT",
        "amount": 2.2732,
        "actual": 0
    },
    "feeCurrency": {
        "currency": "EUR",
        "amount": 0.02,
        "actual": 0
    },
    "networkFeeCurrency": {
        "currency": "USDT",
        "amount": 1.03584,
        "actual": 0
    },
    "displayRate": {
        "base": "USDT",
        "counter": "USD",
        "rate": 1.099771247581
    },
    "exchangeRate": {
        "base": "EUR",
        "counter": "USDT",
        "rate": 0.98834789846
    },
    "address": {
        "address": "0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156",
        "tag": "",
        "protocol": "ERC20",
        "uri": "ethereum:0xdac17f958d2ee523a2206206994597c13d831ec7/transfer?address=0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156&uint256=2.2732E+6",
        "alternatives": []
    },
    "returnUrl": "https://www.yourwebsite.com/status",
    "redirectUrl": "https://pay.sandbox.bvnk.com/payout/954cc08a-d621-4fb3-b2a1-2f76507c8385",
    "transactions": [],
    "refund": null,
    "refunds": [],
    "currencyOptions": null,
    "flow": null,
    "twoStep": true,
    "networkFeeBilledTo": "USER",
    "networkFeeRates": []
}

You can always check the status of a payout by using our GET payment status endpoint.