Send stablecoin payouts
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.
BVNK's v.3 payouts endpoint, POST /payment/v3/payouts, is a single resource that creates, prices, and, when possible, sends a payout. The response depends on the request parameters, not a flag.
- Send a destination currency and a crypto address, and BVNK creates the payout and sends it immediately.
- Leave the destination currency out, and BVNK returns an unpriced payout plus a list of currencies and networks your payee can choose from.
- Send the destination currency and network but not the address, and BVNK returns a priced quote you can still adjust before sending.
- Add
"confirmationRequired": trueto an otherwise complete payout, and BVNK creates it fully priced and accepts the quote, but holds it atPENDING_VERIFICATIONfor your customer to confirm instead of sending it.
Each payout involves three currencies: the originator (your wallet), the beneficiary
(your payee), and an optional display currency oncheckout to show the payment value in familiar terms. You set the amount for one currency; BVNK calculates the others and updates them with each reprice.
You can create a v.3 payout using the following approaches:
- With details known upfront: send everything in one call, and BVNK sends the payout immediately. See Payout with details.
- Without details: send an amount but not the destination, and let your payee choose the currency and network afterwards, either through your own integration or BVNK's hosted page. See Payout without details.
- Quote, then accept: fix one currency, add the beneficiary and destination once you have them, show your customer a firm price, then accept. See Quote flow.
- Pending verification: create a fully priced payout and hold it for your customer to confirm before it sends. See Pending verification.
Create a payout
Both approaches below call the same POST /payment/v3/payouts endpoint. What you get back depends on what you send it, not on a flag:
- With details
- Without details
Payout with details
"With details" means the destination is provided upfront: the beneficiary's currency and crypto address are included in the create call, so BVNK prices and sends the payout in a single step. BVNK still prices the payout as a quote, but accepts it on your behalf at the current rate, so there is no quote for you to accept and no second call. The response shows conversion.type: "QUOTE", and statusHistory[] records PENDING_QUOTE_ACCEPTANCE and PROCESSING at the same timestamp. The rate applied is conversion.allInRate: the mid-market conversion.baseRate adjusted by BVNK's spread, which is disclosed separately in conversion.spread. Use this flow for payroll or similar cases where the destination is already known.
Send the full destination in one call:
{
"reference": "REF46730",
"expiryDuration": "PT30M",
"originator": {
"walletId": "a:25022613287255:zmHs0pg:1"
},
"beneficiary": {
"currency": "USDT",
"requesterIpAddress": "77.71.188.87",
"entity": {
"type": "INDIVIDUAL",
"firstName": "John",
"lastName": "Mirra",
"dateOfBirth": "1984-06-30",
"relationshipType": "THIRD_PARTY",
"address": {
"country": "DE"
}
},
"paymentInstrument": {
"type": "CRYPTO_ADDRESS",
"network": "ETHEREUM",
"address": "0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156",
"tag": null
}
},
"checkout": {
"amount": "10",
"currency": "USD",
"returnUrl": "https://merchant.com/status"
}
}
Key considerations:
referencemust be unique for each payout. Reusing a reference returns auniquevalidation error and does not create a duplicate.beneficiary.paymentInstrument.typeis required. Since v.3 shares this endpoint with fiat payouts, BVNK infers whether the payout is crypto or fiat from this field. There is no request-sidemethod; it is returned on the response.- Only
originator.walletIdis required for the originator. BVNK derivesoriginator.currencyfrom the wallet. - Including a network and address in
beneficiary.paymentInstrumentenables immediate sending. When you provide a network, address, and, if required, tag with a currency, the payout is complete.addressis write-only: the response returns it inbeneficiary.paymentInstrument.addresses[]. beneficiary.entityidentifies the payee. Provide either this orbeneficiary.contactId, not both.- Set only one of
originator.amount,beneficiary.amount, orcheckout.amount. In this example, the display amount is set to 10 USD; the wallet debit (EUR) and payee's USDT amount are derived from this value. The response returns that ask ascheckout.required.originator.actualshows the debit as soon as the payout is sent, andcheckout.actualand every otheractualhave an amount of0.00until the payout reachesCOMPLETED.
You can create a reusable contact and reference it with beneficiary.contactId instead of passing entity for each payout. For more information, see Manage contacts. BVNK rejects requests that include both entity and contactId.
When all required information is provided, BVNK creates and sends the payout in a single call:
{
"id": "b9bf94a8-2e2e-4d29-b8d1-5cdf658e6731",
"reference": "REF46730",
"type": "payment:payout",
"status": "PROCESSING",
"direction": "OUT",
"method": "CRYPTO",
"fees": {
"customerFee": null,
"processingFee": { "estimated": { "currency": "EUR", "amount": "0.09" }, "actual": { "currency": "EUR", "amount": "0.00" } },
"networkFee": { "estimated": { "currency": "EUR", "amount": "1.00" }, "actual": { "currency": "EUR", "amount": "0.00" } }
},
"originator": {
"required": { "currency": "EUR", "amount": "9.21" },
"actual": { "currency": "EUR", "amount": "9.21" },
"walletId": "a:25022613287255:zmHs0pg:1"
},
"beneficiary": {
"required": { "currency": "USDT", "amount": "9.997368" },
"actual": { "currency": "USDT", "amount": "0.00" },
"customerId": null,
"customerReference": null,
"requesterIpAddress": "77.71.188.87",
"entity": {
"type": "INDIVIDUAL",
"firstName": "John",
"lastName": "Mirra",
"dateOfBirth": "1984-06-30",
"relationshipType": "THIRD_PARTY",
"address": {
"country": "DE"
}
},
"paymentInstrument": {
"type": "CRYPTO_ADDRESS",
"network": "ETHEREUM",
"addresses": ["0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156"],
"tag": null
}
},
"conversion": {
"type": "QUOTE",
"baseRate": "1.090945",
"allInRate": "1.085490537307",
"spread": { "percentage": "0.005", "amount": "0.05", "currency": "EUR" },
"validityDuration": "PT30M",
"expiresAt": "2026-03-14T21:13:23Z",
"priceLockDuration": "PT30S",
"priceLockExpiresAt": "2026-03-14T20:43:53Z"
},
"checkout": {
"required": { "currency": "USD", "amount": "10" },
"actual": { "currency": "USD", "amount": "0.00" },
"displayRate": {
"from": "USDT",
"to": "USD",
"rate": "1.000263269292"
},
"redirectUrl": "https://pay.bvnk.com/payout/b9bf94a8-2e2e-4d29-b8d1-5cdf658e6731",
"returnUrl": "https://merchant.com/status"
},
"instructions": [],
"trackingDetails": [],
"labels": [],
"relatedPayments": [],
"statusHistory": [
{ "status": "PENDING_QUOTE_ACCEPTANCE", "timestamp": "2026-03-14T20:43:23Z" },
{ "status": "PROCESSING", "timestamp": "2026-03-14T20:43:23Z" }
],
"flow": "default",
"metadata": {},
"expiryDuration": "PT30M",
"expiresAt": "2026-03-14T21:13:23Z",
"updatedAt": "2026-03-14T20:43:23Z",
"createdAt": "2026-03-14T20:43:23Z"
}
A payout with details doesn't wait at PENDING_QUOTE_ACCEPTANCE: BVNK accepts the quote at creation, and the payout moves straight to PROCESSING. Conditional statuses are shown as dashed boxes. For what each status means, see Payment statuses.

Integrate advanced payout capabilities
Two flows are available here:
- Quote: present your customer with a firm, adjustable price before committing, fixing either side of the trade:
- Use fixed debit to spend a specific amount without yet knowing the destination.
- Use fixed credit to decide exactly what the payee receives and let your own cost float.
- Pending verification: create a fully priced payout with the quote accepted, and hold it for your customer to confirm before it sends, instead of sending immediately.
- Quote flow
- Pending verification
Create an incomplete payout, refine the details, and accept when ready to send:
-
Create the quote by sending the
POST /payment/v3/payoutsrequest.Fix an amount on either the originator or beneficiary side:
originator.amountcreates a fixed debit quote, specifying the exact amount to debit from your wallet.beneficiary.amountcreates a fixed credit quote, ensuring the payee receives the specified amount.
- Fix the debit (originator.amount)
- Fix the credit (beneficiary.amount)
{
"reference": "REF88214",
"originator": {
"amount": "25.00",
"walletId": "a:24072237783989:Unkx9kW:1"
},
"beneficiary": {
"currency": "USDT",
"requesterIpAddress": "172.16.254.1",
"paymentInstrument": {
"type": "CRYPTO_ADDRESS",
"network": "ETHEREUM"
}
}
}
{
"id": "019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd",
"reference": "REF88214",
"type": "payment:payout",
"status": "PENDING_QUOTE_ACCEPTANCE",
"direction": "OUT",
"method": "CRYPTO",
"fees": {
"customerFee": null,
"processingFee": { "estimated": { "currency": "USD", "amount": "0.25" }, "actual": { "currency": "USD", "amount": "0.00" } },
"networkFee": { "estimated": { "currency": "USD", "amount": "1.62" }, "actual": { "currency": "USD", "amount": "0.00" } }
},
"originator": {
"required": { "currency": "USD", "amount": "25.00" },
"actual": { "currency": "USD", "amount": "0.00" },
"walletId": "a:24072237783989:Unkx9kW:1"
},
"beneficiary": {
"required": { "currency": "USDT", "amount": "23.742875" },
"actual": { "currency": "USDT", "amount": "0.00" },
"customerId": null,
"customerReference": null,
"requesterIpAddress": "172.16.254.1",
"paymentInstrument": {
"type": "CRYPTO_ADDRESS",
"network": "ETHEREUM",
"addresses": [],
"tag": null
}
},
"conversion": {
"type": "QUOTE",
"baseRate": "0.954488",
"allInRate": "0.949715",
"spread": { "percentage": "0.005", "amount": "0.13", "currency": "USD" },
"digest": "c41f8ae2b93d07f5",
"validityDuration": "PT1H",
"expiresAt": "2026-08-18T15:25:00Z",
"priceLockDuration": "PT30S",
"priceLockExpiresAt": "2026-08-18T14:25:30Z"
},
"instructions": [],
"trackingDetails": [],
"labels": [],
"relatedPayments": [],
"statusHistory": [
{ "status": "PENDING_QUOTE_ACCEPTANCE", "timestamp": "2026-08-18T14:25:00Z" }
],
"flow": "default",
"metadata": {},
"expiryDuration": "PT1H",
"expiresAt": "2026-08-18T15:25:00Z",
"updatedAt": "2026-08-18T14:25:00Z",
"createdAt": "2026-08-18T14:25:00Z"
}
If you already know who you're paying, send beneficiary.entity or contactId and beneficiary.paymentInstrument.network in step 1 instead of waiting until step 4. This is the same fixed debit sequence, but only the destination address stays outstanding. Resolving the entity early screens compliance and confirms fees before your customer sees a price. relationshipType can change crypto pricing, so an entity added later may reprice the fee. On fiat, it is the only way to get fees at all, since fiat cannot price a fee without a beneficiary.
-
If the quote is about to expire and neither the amount nor the beneficiary needs to change, refresh it. Include the last
conversion.digestso BVNK reprices the correct quote:Request: POST /payment/v3/payouts/019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd/action{"type": "REFRESH_QUOTE","digest": "c41f8ae2b93d07f5"}The payout remains in
PENDING_QUOTE_ACCEPTANCE, with a new rate and a new digest:Response: key fields after REFRESH_QUOTE{"id": "019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd","reference": "REF88214","type": "payment:payout","status": "PENDING_QUOTE_ACCEPTANCE","direction": "OUT","method": "CRYPTO","fees": {"customerFee": null,"processingFee": { "estimated": { "currency": "USD", "amount": "0.25" }, "actual": { "currency": "USD", "amount": "0.00" } },"networkFee": { "estimated": { "currency": "USD", "amount": "1.62" }, "actual": { "currency": "USD", "amount": "0.00" } }},"originator": {"required": { "currency": "USD", "amount": "25.00" },"actual": { "currency": "USD", "amount": "0.00" },"walletId": "a:24072237783989:Unkx9kW:1"},"beneficiary": {"required": { "currency": "USDT", "amount": "23.705250" },"actual": { "currency": "USDT", "amount": "0.00" },"customerId": null,"customerReference": null,"requesterIpAddress": "172.16.254.1","paymentInstrument": {"type": "CRYPTO_ADDRESS","network": "ETHEREUM","addresses": [],"tag": null}},"conversion": {"type": "QUOTE","baseRate": "0.952975","allInRate": "0.948210","spread": { "percentage": "0.005", "amount": "0.13", "currency": "USD" },"digest": "7b21e0c4d95a3f18","validityDuration": "PT59M18S","expiresAt": "2026-08-18T15:25:00Z","priceLockDuration": "PT30S","priceLockExpiresAt": "2026-08-18T14:26:12Z"},"instructions": [],"trackingDetails": [],"labels": [],"relatedPayments": [],"statusHistory": [{ "status": "PENDING_QUOTE_ACCEPTANCE", "timestamp": "2026-08-18T14:25:00Z" }],"flow": "default","metadata": {},"expiryDuration": "PT1H","expiresAt": "2026-08-18T15:25:00Z","updatedAt": "2026-08-18T14:25:42Z","createdAt": "2026-08-18T14:25:00Z"}conversion.digestdigestis a fingerprint of the current quote. BVNK issues a new one on create, on everyREFRESH_QUOTE, and on everyPATCH, because aPATCHreprices the whole quote whether or not you change an amount.REFRESH_QUOTErequires the latest digest and rejects a stale one, so a reprice always acts on the quote your customer last saw.ACCEPT_QUOTEdoesn't need a digest and doesn't issue a new one. -
If your customer wants to adjust the amount, update it by sending a
PATCH /payment/v3/payouts/{id}request with the same field you originally fixed. APATCHreprices the entire quote, even if the amount remains unchanged:Request: PATCH /payment/v3/payouts/019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd{"originator": {"amount": "30.00"}}Response: key fields after changing the amount{"id": "019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd","reference": "REF88214","type": "payment:payout","status": "PENDING_QUOTE_ACCEPTANCE","direction": "OUT","method": "CRYPTO","fees": {"customerFee": null,"processingFee": { "estimated": { "currency": "USD", "amount": "0.30" }, "actual": { "currency": "USD", "amount": "0.00" } },"networkFee": { "estimated": { "currency": "USD", "amount": "1.62" }, "actual": { "currency": "USD", "amount": "0.00" } }},"originator": {"required": { "currency": "USD", "amount": "30.00" },"actual": { "currency": "USD", "amount": "0.00" },"walletId": "a:24072237783989:Unkx9kW:1"},"beneficiary": {"required": { "currency": "USDT", "amount": "28.446300" },"actual": { "currency": "USDT", "amount": "0.00" },"customerId": null,"customerReference": null,"requesterIpAddress": "172.16.254.1","paymentInstrument": {"type": "CRYPTO_ADDRESS","network": "ETHEREUM","addresses": [],"tag": null}},"conversion": {"type": "QUOTE","baseRate": "0.952975","allInRate": "0.948210","spread": { "percentage": "0.005", "amount": "0.15", "currency": "USD" },"digest": "e5c8a7f2b1904d63","validityDuration": "PT58M25S","expiresAt": "2026-08-18T15:25:00Z","priceLockDuration": "PT30S","priceLockExpiresAt": "2026-08-18T14:27:05Z"},"instructions": [],"trackingDetails": [],"labels": [],"relatedPayments": [],"statusHistory": [{ "status": "PENDING_QUOTE_ACCEPTANCE", "timestamp": "2026-08-18T14:25:00Z" }],"flow": "default","metadata": {},"expiryDuration": "PT1H","expiresAt": "2026-08-18T15:25:00Z","updatedAt": "2026-08-18T14:26:35Z","createdAt": "2026-08-18T14:25:00Z"} -
Provide the beneficiary and destination address by sending a
PATCH /payment/v3/payouts/{id}request while the payout is still a quote. This allows your customer to review a final priced quote before committing. When updating a nested object, include the entire object rather than a single field:Request: PATCH /payment/v3/payouts/019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd{"beneficiary": {"entity": {"type": "INDIVIDUAL","firstName": "John","lastName": "Doe","dateOfBirth": "1984-06-30","relationshipType": "THIRD_PARTY","address": {"addressLine1": "Hauptstrasse 42","addressLine2": null,"city": "Munich","region": "Bavaria","postCode": "80331","country": "DE"}},"paymentInstrument": {"type": "CRYPTO_ADDRESS","network": "ETHEREUM","address": "0x02ae4f91C7B3d0521a5E9c3b7F84D6a1c9E1C156","tag": null}}}Response: PATCH /payment/v3/payouts/019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd{"id": "019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd","reference": "REF88214","type": "payment:payout","status": "PENDING_QUOTE_ACCEPTANCE","direction": "OUT","method": "CRYPTO","fees": {"customerFee": null,"processingFee": { "estimated": { "currency": "USD", "amount": "0.30" }, "actual": { "currency": "USD", "amount": "0.00" } },"networkFee": { "estimated": { "currency": "USD", "amount": "1.62" }, "actual": { "currency": "USD", "amount": "0.00" } }},"originator": {"required": { "currency": "USD", "amount": "30.00" },"actual": { "currency": "USD", "amount": "0.00" },"walletId": "a:24072237783989:Unkx9kW:1"},"beneficiary": {"required": { "currency": "USDT", "amount": "28.446300" },"actual": { "currency": "USDT", "amount": "0.00" },"customerId": null,"customerReference": null,"requesterIpAddress": "172.16.254.1","entity": {"type": "INDIVIDUAL","firstName": "John","lastName": "Doe","dateOfBirth": "1984-06-30","relationshipType": "THIRD_PARTY","address": {"addressLine1": "Hauptstrasse 42","addressLine2": null,"city": "Munich","region": "Bavaria","postCode": "80331","country": "DE"}},"paymentInstrument": {"type": "CRYPTO_ADDRESS","network": "ETHEREUM","addresses": ["0x02ae4f91C7B3d0521a5E9c3b7F84D6a1c9E1C156"],"tag": null}},"conversion": {"type": "QUOTE","baseRate": "0.952975","allInRate": "0.948210","spread": { "percentage": "0.005", "amount": "0.15", "currency": "USD" },"digest": "a90d4e17c6b52f8a","validityDuration": "PT57M20S","expiresAt": "2026-08-18T15:25:00Z","priceLockDuration": "PT30S","priceLockExpiresAt": "2026-08-18T14:28:10Z"},"instructions": [],"trackingDetails": [],"labels": [],"relatedPayments": [],"statusHistory": [{ "status": "PENDING_QUOTE_ACCEPTANCE", "timestamp": "2026-08-18T14:25:00Z" }],"flow": "default","metadata": {},"expiryDuration": "PT1H","expiresAt": "2026-08-18T15:25:00Z","updatedAt": "2026-08-18T14:27:40Z","createdAt": "2026-08-18T14:25:00Z"}A
PATCHreprices the whole quote, so the response carries a newconversion.digestand a new rate lock,conversion.priceLockExpiresAt, even when the price doesn't change. Adding the address doesn't send the payout: only accepting the quote does. Present this response to your customer so they can review the final rate, fees, and payee details before proceeding. -
Once your customer confirms, accept the quote by sending the
POST /payment/v3/payouts/{id}/actionrequest with"type": "ACCEPT_QUOTE".Request: POST /payment/v3/payouts/019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd/action{"type": "ACCEPT_QUOTE"}Response: POST /payment/v3/payouts/019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd/action{"id": "019f2a3b-7c41-7e2a-9b55-4d1e8f0aabcd","reference": "REF88214","type": "payment:payout","status": "PROCESSING","direction": "OUT","method": "CRYPTO","fees": {"customerFee": null,"processingFee": { "estimated": { "currency": "USD", "amount": "0.30" }, "actual": { "currency": "USD", "amount": "0.00" } },"networkFee": { "estimated": { "currency": "USD", "amount": "1.62" }, "actual": { "currency": "USD", "amount": "0.00" } }},"originator": {"required": { "currency": "USD", "amount": "30.00" },"actual": { "currency": "USD", "amount": "30.00" },"walletId": "a:24072237783989:Unkx9kW:1"},"beneficiary": {"required": { "currency": "USDT", "amount": "28.446300" },"actual": { "currency": "USDT", "amount": "0.00" },"customerId": null,"customerReference": null,"requesterIpAddress": "172.16.254.1","entity": {"type": "INDIVIDUAL","firstName": "John","lastName": "Doe","dateOfBirth": "1984-06-30","relationshipType": "THIRD_PARTY","address": {"addressLine1": "Hauptstrasse 42","addressLine2": null,"city": "Munich","region": "Bavaria","postCode": "80331","country": "DE"}},"paymentInstrument": {"type": "CRYPTO_ADDRESS","network": "ETHEREUM","addresses": ["0x02ae4f91C7B3d0521a5E9c3b7F84D6a1c9E1C156"],"tag": null}},"conversion": {"type": "QUOTE","baseRate": "0.952975","allInRate": "0.948210","spread": { "percentage": "0.005", "amount": "0.15", "currency": "USD" },"digest": "a90d4e17c6b52f8a","validityDuration": "PT57M20S","expiresAt": "2026-08-18T15:25:00Z","priceLockDuration": "PT30S","priceLockExpiresAt": "2026-08-18T14:28:10Z"},"instructions": [],"trackingDetails": [],"labels": [],"relatedPayments": [],"statusHistory": [{ "status": "PENDING_QUOTE_ACCEPTANCE", "timestamp": "2026-08-18T14:25:00Z" },{ "status": "PROCESSING", "timestamp": "2026-08-18T14:28:02Z" }],"flow": "default","metadata": {},"expiryDuration": "PT1H","expiresAt": "2026-08-18T15:25:00Z","updatedAt": "2026-08-18T14:28:02Z","createdAt": "2026-08-18T14:25:00Z"}There is no separate confirmation or send step; accepting the quote initiates the payout. Ensure
beneficiary.entityorcontactIdis set before callingACCEPT_QUOTE, either during creation or via a priorPATCH, or the action will fail.Quotes expire with the payoutconversion.expiresAtmatches the payout's ownexpiresAt, set fromexpiryDurationwhen you create the payout, andconversion.validityDurationshows the time left. Accepting or refreshing after it has passed fails. The rate itself is locked forconversion.priceLockDuration, 30 seconds, untilconversion.priceLockExpiresAt. Every reprice starts a new rate lock.
Check payout status
Send a GET request to /payment/v3/payouts/{id} at any point to see the payout's current state:
{
"id": "b9bf94a8-2e2e-4d29-b8d1-5cdf658e6731",
"reference": "REF46730",
"type": "payment:payout",
"status": "COMPLETED",
"direction": "OUT",
"method": "CRYPTO",
"fees": {
"customerFee": null,
"processingFee": { "estimated": { "currency": "EUR", "amount": "0.09" }, "actual": { "currency": "EUR", "amount": "0.09" } },
"networkFee": { "estimated": { "currency": "EUR", "amount": "1.00" }, "actual": { "currency": "EUR", "amount": "1.00" } }
},
"originator": {
"required": { "currency": "EUR", "amount": "9.21" },
"actual": { "currency": "EUR", "amount": "9.21" },
"walletId": "a:25022613287255:zmHs0pg:1"
},
"beneficiary": {
"required": { "currency": "USDT", "amount": "9.997368" },
"actual": { "currency": "USDT", "amount": "9.997368" },
"customerId": null,
"customerReference": null,
"requesterIpAddress": "77.71.188.87",
"entity": {
"type": "INDIVIDUAL",
"firstName": "John",
"lastName": "Mirra",
"dateOfBirth": "1984-06-30",
"relationshipType": "THIRD_PARTY",
"address": {
"country": "DE"
}
},
"paymentInstrument": {
"type": "CRYPTO_ADDRESS",
"network": "ETHEREUM",
"addresses": ["0x02ae6765C6991813a3EAa86fe63ebBCA1c9EC156"],
"tag": null
}
},
"conversion": {
"type": "QUOTE",
"baseRate": "1.090945",
"allInRate": "1.085490537307",
"spread": { "percentage": "0.005", "amount": "0.05", "currency": "EUR" },
"validityDuration": "PT30M",
"expiresAt": "2026-03-14T21:13:23Z",
"priceLockDuration": "PT30S",
"priceLockExpiresAt": "2026-03-14T20:43:53Z"
},
"checkout": {
"required": { "currency": "USD", "amount": "10" },
"actual": { "currency": "USD", "amount": "10" },
"displayRate": {
"from": "USDT",
"to": "USD",
"rate": "1.000263269292"
},
"redirectUrl": "https://pay.bvnk.com/payout/b9bf94a8-2e2e-4d29-b8d1-5cdf658e6731",
"returnUrl": "https://merchant.com/status"
},
"instructions": [],
"trackingDetails": [
{
"amount": "9.997368",
"currency": "USDT",
"hash": "0x8f14c7b3e5a92d0641fbe7c3a8d15e29047b6c1f9e3a52d8b704c6fa1e93b528",
"network": "ETHEREUM",
"createdAt": "2026-03-14T20:45:36Z",
"confirmedAt": "2026-03-14T20:47:11Z"
}
],
"labels": [],
"relatedPayments": [],
"statusHistory": [
{ "status": "PENDING_QUOTE_ACCEPTANCE", "timestamp": "2026-03-14T20:43:23Z" },
{ "status": "PROCESSING", "timestamp": "2026-03-14T20:43:23Z" },
{ "status": "COMPLETED", "timestamp": "2026-03-14T20:47:11Z" }
],
"flow": "default",
"metadata": {},
"expiryDuration": "PT30M",
"expiresAt": "2026-03-14T21:13:23Z",
"updatedAt": "2026-03-14T20:47:11Z",
"createdAt": "2026-03-14T20:43:23Z"
}
Once the payout reaches COMPLETED, every actual is filled in, on originator, beneficiary, checkout, and each fee, and trackingDetails[] carries the on-chain transaction. Refer to statusHistory[] for a complete audit trail instead of relying on a single status value. For every status a payout can pass through, see Payment statuses.
Provide additional party information
You may also need to provide additional party information to comply with the Travel Rule. See the Provide additional party information guide for more details.
Handle errors
A validation error, such as a duplicate reference, is rejected before the payout is created:
{
"requestId": "fd3b64b97db85a7ebab39d5a1fb20867",
"errorList": [
{
"parameter": "reference",
"code": "unique",
"message": "Duplicate Reference"
}
]
}
The same error format is returned if beneficiary includes both entity and contactId in the same request. Provide one or the other, not both.
If a payout fails after processing begins, for example due to insufficient wallet balance after network fees are applied, it does not return an error response. Instead, it moves to status: "FAILED", which is visible via GET or the webhook. Refer to statusHistory[] for the transition timestamp.
Payout webhook
To receive notifications when a payout status changes, subscribe to payment:v3:payout:status-change. This event covers all state transitions, including refunds (payouts with labels: ["REFUND"]). Read the current state from data.status and the full history from data.statusHistory[] instead of relying on a single value.