Skip to main content

Multi-destination payments

A multi-destination payment order sends part of the payment to your wallet and the rest to the wallet of one of your partners. Both transfers happen in the same blockchain transaction, so neither side depends on the other settling first.

A partner does not need an account on Bitpayway. If a partner happens to be a Bitpayway business as well, the wallet you register for the link is used only for your multi-destination orders and never changes how that business receives its own payments.

Standard orders are unchanged. Omitting paymentModel keeps the existing behaviour and the existing response shape.

How multi-destination appears in the API​

In the API, multi-destination payments are called split. Whenever that name appears in a field or route, it refers to this feature:

Where it appearsWhat it is
paymentModelOptional POST /api/order field that sets the order type. Send "split" to create a multi-destination order; without it, the order is a standard one.
split objectThe order's split details: the partner and their share. Sent when creating the order and returned in queries and webhooks.
splitEnabledField of each token in GET /api/currency-token. true means the token accepts multi-destination payments.
/api/split/... routesRoutes to register partners and multi-destination wallets, such as POST /api/split/partners and PATCH /api/split/wallet. The full list is in Configuring through the API.

What the current version supports​

SupportedNot supported
One partner per orderSeveral partners in the same order
Allocation expressed as a gross amountAllocation expressed as a percentage in the API
Partial payments and overpaymentsChanging the allocation after the order is created

If your interface offers a percentage, convert it to a gross amount before creating the order.

Wallet model and responsibilities​

Multi-destination and standard payments use independent wallet registrations. Changing a multi-destination wallet does not change the destination of standard payments, and changing a standard settlement wallet does not affect multi-destination payments.

ConfigurationScopeWhere it is managed
Business multi-destination walletOne business and token/provider; reused for every partnerBusiness dashboard or API
Partner link and walletOne business-partner-token combinationAPI only
Standard settlement walletOne business and token for standard paymentsBusiness dashboard

Your business's multi-destination wallet is configured for each token and its enabled multi-destination provider. You register it once and the registry reuses it for every partner linked to your business. Adding a partner does not require registering your business wallet again. Changing your business wallet changes the destination of your business's share for future multi-destination payments with every partner on that token.

A partner wallet is deliberately narrower: it belongs to one business-partner-token combination. If the same partner works with another business, that other link has its own wallet configuration. Partner links and wallets can only be created, changed, activated or deactivated through the API.

Both wallets and the partner link must be valid even when one share is zero. Neither destination wallet can be the payer of the payment transaction or the provider contract itself; your business and the partner may use the same destination address.

Configure multi-destination payments before the first order​

Complete these three stages for every token you intend to accept:

  1. select a token with multi-destination support;
  2. register and enable your business's multi-destination wallet for that token; and
  3. create the partner link and register that partner's wallet.

Your business wallet and the partner wallet must both be registered on-chain before an order using that business-partner-token combination can be created.

1. Select a token with multi-destination support​

The dashboard displays a wallet card for multi-destination payments only when the token has an enabled multi-destination provider. A server integration can discover the same availability with GET /api/currency-token: use a token whose splitEnabled field is true and keep its contractId as the tokenContractId used by the wallet routes.

Configuration is independent for each token. Repeat the remaining stages for USDT, USDC or any other token you want to use. If a provider later starts using a replacement wallet registry, register your business and partner wallets in that new registry as well.

2. Register your business's multi-destination wallet for the token in the dashboard​

Open the business Configuration page and find Split settlement wallets. In the card for the selected token:

  1. enter the wallet that will receive your business's share;
  2. connect a browser wallet;
  3. select Update split wallet and approve the transaction; and
  4. wait for the card to report Enabled. Use Check status to refresh it.

This saves the wallet on the blockchain.

The wallet you enter does not need to be the same as the connected wallet you are using to perform this operation.

You can integrate with your application to perform this operation using PATCH /api/split/wallet.

3. Create the partner and register its wallet through the API​

Partner management is server-side and requires Authorization: ApiKey <your-api-key>. First create the link with POST /api/split/partners:

{
"name": "Marketplace partner",
"external_id": "marketplace-seller-42"
}

external_id is optional and accepts 1 to 255 characters. When set, it is unique among your business's partners. Reusing it within the same business returns 409; another business may use the same value. A partner created without it returns "external_id": null.

Use the returned partner id to save and authorize its wallet for the selected token with PATCH /api/split/partners/{partnerId}/wallet. Repeat the partner wallet registration for every token that partner will use.

Setting a partner link to active:false and submitting its authorization blocks new multi-destination orders and payments that use the link. Reactivation requires another authorization. Changing either wallet affects future payments, including payments toward orders that already exist.

Authorization and on-chain status​

Every wallet change has two states: the configuration saved by Bitpayway and the state currently registered on-chain. Applying a change requires both saving the desired wallet and submitting the authorized registry transaction.

The dashboard automates both actions for your business's multi-destination wallet for that token after the user approves the browser-wallet transaction. When using the API—for either your business or a partner—your integration or relayer must submit the returned authorization. The API call itself does not spend gas or send the transaction.

The wallet PATCH response contains everything needed to send the transaction: network, walletRegisterAddress, the registry abi, the functionName to call and its args already in call order.

functionName is the name of the wallet registry contract method you must call; it is part of the returned abi. Call that method on walletRegisterAddress, on the network in network.chainId, passing args. The value is setClientWalletWithAuth for your business's multi-destination wallet for that token, and setSplitWalletWithAuth for a partner wallet and active state; use the returned value instead of choosing it yourself.

The signed signatureParams remain available if you prefer to build the call yourself, and expiresAt is the ISO 8601 form of signatureParams.deadline.

The submitting account is only a relayer. It pays gas but does not need to match either receiving wallet. The signature prevents it from changing the business, token, destination, partner state or deadline.

An authorization expires after ten minutes and can be consumed only once. If it expires, is rejected or uses an already-consumed nonce, request a new one instead of resubmitting it. Until the transaction is confirmed, the saved configuration and the on-chain state differ and isEnabled remains false.

The status response separates those states: configured is the saved value, while wallet and active are read from the blockchain. isEnabled:true means they match. For a confirmed partner deactivation it can therefore be true while active is false; that link still cannot receive new multi-destination payments.

Configuring through the API​

A server integration can configure your business wallet as an alternative to the dashboard and must be used for all partner configuration. Send Authorization: ApiKey <your-api-key>. The API key identifies the business, so these routes do not accept a business ID:

OperationRoute
Discover tokensGET /api/currency-token
List partnersGET /api/split/partners
Create a partnerPOST /api/split/partners
Save your multi-destination wallet and get an authorizationPATCH /api/split/wallet
Save a partner wallet and get an authorizationPATCH /api/split/partners/{partnerId}/wallet
Reissue the authorization for your walletPOST /api/split/wallet/authorization
Reissue the authorization for a partner walletPOST /api/split/partners/{partnerId}/wallet/authorization
Check the registry state of your walletGET /api/split/wallet/status
Check the registry state of a partner walletGET /api/split/partners/{partnerId}/wallet/status

GET /api/split/partners accepts the optional exact-match filters id (the public partner UUID) and external_id. The filters can be combined and never return partners belonging to another business. For example:

GET /api/split/partners?external_id=marketplace-seller-42
GET /api/split/partners?id=9f1c2d64-5717-4562-b3fc-2c963f66afa6

Use the contractId of a token whose splitEnabled field is true as the tokenContractId. Wallet requests have the following body:

{
"tokenContractId": "28a555aa-d6bb-4a0b-9266-0b6668f824b5",
"wallet": "0x1111111111111111111111111111111111111111",
"active": true
}

active applies to partner links and defaults to true. Omit it when configuring your business's multi-destination wallet for the token, which cannot be deactivated.

The PATCH response returns the registry address, ABI and signed parameters for the saved configuration. Your integration or relayer must submit that authorization to the registry before it expires, then poll the status route until isEnabled is true. If the authorization expires or the transaction is not submitted, send tokenContractId to the authorization route to reissue it. The API does not spend gas or submit the blockchain transaction for you.

For ready-to-use ethers examples, see the optional technical reference Submitting wallet authorizations.

Creating an order​

Add paymentModel and split to the existing POST /api/order request:

{
"requestId": "2f3c9d2c-1b75-4e9d-9b2f-67d0a9c3c7d1",
"description": "Order #1234",
"amount": "1000",
"network": "sepolia",
"token": "USDC",
"paymentModel": "split",
"split": {
"partnerId": "9f1c2d64-5717-4562-b3fc-2c963f66afa6",
"partnerAmount": "300"
}
}
  • partnerId is the UUID returned by POST /api/split/partners.
  • partnerAmount is the partner's gross share, before the platform fee. It is a decimal string in the display unit of the token, between zero and amount, with at most the number of decimals the token supports.
  • amount must be greater than zero.

The order fixes the provider, the partner and the allocation when it is created. Reuse the same requestId to repeat the same creation safely; the existing order is returned. A 409 means that requestId was already used with different data.

Reading an order​

Multi-destination orders carry the following extra fields in GET /api/order, GET /api/order/request/{requestId} and in webhooks:

FieldMeaning
paymentModelsplit for multi-destination orders; absent on standard orders.
split.partnerIdUUID of the partner link.
split.partnerCodeIdOn-chain identifier of the partner link.
split.partnerAmountGross share agreed when the order was created.
settlementStatuspending, matched or mismatch.
settlementVersionIncreases whenever the confirmed amounts change.

The amounts are decimal strings in the order token:

FieldMeaning
paidAmountGross amount confirmed for the order.
netAmountAmount effectively received by you.
partnerNetAmountAmount effectively received by the partner.
partnerGrossAmountGross amount accumulated for the partner.
feeNominal total platform fee.
clientCommissionNominal fee charged on your share.
partnerCommissionNominal fee charged on the partner's share.
commissionReceivedAmount effectively received by the platform.
{
"order": {
"id": "7f7f5a2a-5c4f-4c6b-9cbb-1f0f4b4e42f2",
"date": "2026-02-12T18:12:43.384Z",
"requestId": "2f3c9d2c-1b75-4e9d-9b2f-67d0a9c3c7d1",
"clientId": "12345",
"orderId": "42",
"description": "Order #1234",
"amount": "1000",
"status": "partial paid",
"gatewayUrl": "https://pay.example.com/?id=7f7f5a2a-5c4f-4c6b-9cbb-1f0f4b4e42f2",
"paymentModel": "split",
"settlementStatus": "pending",
"settlementVersion": 1,
"split": {
"partnerId": "9f1c2d64-5717-4562-b3fc-2c963f66afa6",
"partnerCodeId": "7",
"partnerAmount": "300"
},
"paidAmount": "500",
"netAmount": "346.5",
"partnerNetAmount": "148.5",
"partnerGrossAmount": "150",
"fee": "5",
"clientCommission": "3.5",
"partnerCommission": "1.5",
"commissionReceived": "5"
}
}

Use netAmount and partnerNetAmount as the amounts actually received rather than rebuilding them from the gross amount minus the fee.

Your business statistics count only your own share. Adding your share to the partner's does not produce your net revenue.

Fees and partial payments​

The platform fee is charged on each contribution and split between you and the partner according to each share. A partial payment is divided in the same proportion as the whole order. See how the calculation works, with an example, in Fees.

Two payments quoted against the same confirmed total can differ by rounding and need reconciliation.

Confirmation and divergence​

A successful transaction receipt is not an approved order. Bitpayway finalizes a multi-destination payment only after twelve block confirmations. Meanwhile, a payment that completes the order with the agreed division leaves it paid waiting confirmations, and a partial payment leaves the status unchanged. The order accepts payments for 30 minutes after it is created.

The contracts let the payer choose the division that is submitted. Bitpayway detects a division that diverges from the agreed one after the transfers have already happened and does not approve such a payment automatically. The on-chain transfers cannot be reversed by the platform.

This is what settlementStatus reports:

  • pending: no confirmed divergence, and the order may still be settling.
  • matched: the confirmed amounts follow the agreed allocation.
  • mismatch: the confirmed amounts diverge and the order needs reconciliation with your partner.

Settlement is a financial dimension and does not replace the commercial status. An order that was already approved stays paid if a later payment brings a divergent division; it is flagged as mismatch, and its totals and settlementVersion are updated. A canceled order stays canceled even if funds arrive afterwards.

Webhooks​

A multi-destination order sends the fields above inside the existing webhook notification, verified with the same HMAC signature. Two differences matter for multi-destination orders:

  • A settlement change can produce a webhook after a terminal status, so an order can be notified more than once.
  • settlementVersion identifies the version of the amounts. A response to an older notification does not confirm delivery of a newer one.

Handle repeated notifications idempotently and do not repeat a commercial fulfilment on every financial update. See the webhook guide for the request format and signature verification.