Paystack Multi-Split Payments Explained
Paystack multi-split lets you divide a single customer payment among three or more parties. You create a Transaction Split object that lists subaccounts and their shares (percentage or flat), then pass the resulting split_code when initializing a transaction. Paystack settles each subaccount directly. Your main account receives whatever portion is not allocated to subaccounts.
When You Need Multi-Split
Standard split payments on Paystack work between two parties: your main account and one subaccount. That covers the common marketplace case where a buyer purchases from a single seller and the platform takes a cut. But many real-world transactions involve more than two parties.
Here are the situations where multi-split becomes necessary:
- Food delivery: The customer's payment needs to reach the restaurant (food cost), the delivery rider (delivery fee), and the platform (commission). Three parties, one payment.
- Referral marketplaces: The vendor receives their share, the referring agent gets a referral commission, and the platform keeps the rest. Three parties.
- Insurance distribution: The premium payment splits between the insurer, the broker, and the distribution platform.
- Collaborative services: Two freelancers work on a project together. The client pays once, and the money splits between freelancer A, freelancer B, and the platform.
- Regional sales models: A vendor gets 70%, the regional sales agent who brought them onto the platform gets 10%, and the platform keeps 20%.
If every transaction on your platform involves exactly two parties (vendor and platform), use single split. If any transaction involves three or more, you need multi-split. Do not use multi-split for two-party transactions. It adds an extra API call (creating the split group) for no benefit.
Creating a Transaction Split Group
A Transaction Split group defines the participants and their shares. You create it with a POST to the /split endpoint, then use the returned split_code in transaction initialization.
// Create a multi-split group for a food delivery order
async function createOrderSplit(restaurantCode, riderCode) {
var response = await fetch('https://api.paystack.co/split', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Order Split - ' + Date.now(),
type: 'percentage',
currency: 'NGN',
subaccounts: [
{
subaccount: restaurantCode,
share: 65,
},
{
subaccount: riderCode,
share: 15,
},
],
bearer_type: 'account',
bearer_subaccount: '',
}),
});
var data = await response.json();
if (data.status) {
// data.data.split_code => "SPL_xyz789"
// Platform gets the residual: 100 - 65 - 15 = 20%
return data.data.split_code;
} else {
throw new Error('Split creation failed: ' + data.message);
}
}
The key fields in the creation request:
- name: A label for the split group. Useful for identification in the dashboard. Make it descriptive enough that your operations team can tell what it is for.
- type: Either
percentageorflat. This applies to all subaccounts in the group. You cannot mix percentage and flat within one split group. - currency: The currency for this split group. Must match the currency of the transactions that will use it.
- subaccounts: An array of objects, each with a
subaccountcode and ashare. For percentage type, shares are percentages. For flat type, shares are amounts in the smallest currency unit. - bearer_type: Who absorbs the Paystack fee. Options:
account,subaccount, orall-proportional(fee is shared proportionally among the subaccounts). Ifsubaccount, you must also setbearer_subaccountto specify which one.
Using the Split Code in a Transaction
Once you have a split_code, pass it when initializing the transaction instead of the subaccount parameter.
// Initialize a transaction with a multi-split group
async function chargeWithMultiSplit(customerEmail, amountInKobo, splitCode, orderId) {
var response = await fetch('https://api.paystack.co/transaction/initialize', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: customerEmail,
amount: amountInKobo,
split_code: splitCode,
reference: 'order_' + orderId + '_' + Date.now(),
metadata: {
order_id: orderId,
custom_fields: [
{
display_name: 'Order ID',
variable_name: 'order_id',
value: String(orderId),
},
],
},
}),
});
var data = await response.json();
if (data.status) {
return data.data.authorization_url;
} else {
throw new Error('Transaction initialization failed: ' + data.message);
}
}
Important: do not pass both subaccount and split_code in the same transaction. Use one or the other. If you pass split_code, the split group definition takes over completely. Any subaccount, transaction_charge, or bearer parameters are ignored in favor of the split group's configuration.
The customer experience is identical to a regular payment. They see one charge for the full amount. The multi-split happens entirely at the settlement layer.
Percentage vs Flat in Multi-Split
The type field on the split group determines how shares are interpreted. The choice affects your margin math and how the split scales with transaction size.
Percentage type
Each subaccount's share is a percentage of the transaction amount. The residual (whatever is left after all subaccount shares) goes to your main account.
Example: customer pays 10,000 NGN. Restaurant share is 65%, rider share is 15%.
- Restaurant gets: 10,000 x 65% = 6,500 NGN
- Rider gets: 10,000 x 15% = 1,500 NGN
- Platform gets: 10,000 - 6,500 - 1,500 = 2,000 NGN (20% residual)
Flat type
Each subaccount's share is a fixed amount in the smallest currency unit. The residual goes to your main account.
Example: customer pays 10,000 NGN (1,000,000 kobo). Restaurant share is 650,000 kobo, rider share is 150,000 kobo.
- Restaurant gets: 6,500 NGN
- Rider gets: 1,500 NGN
- Platform gets: 10,000 - 6,500 - 1,500 = 2,000 NGN
The numbers look the same in this example, but they diverge at different price points. If the order were 5,000 NGN:
- Percentage: restaurant gets 3,250, rider gets 750, platform gets 1,000
- Flat: restaurant gets 6,500, rider gets 1,500, platform gets... negative 3,000. The flat amounts exceed the transaction amount.
With flat type, you must ensure the sum of all subaccount shares does not exceed the transaction amount. Paystack will reject or miscalculate the split if flat shares exceed the total. Percentage type avoids this problem because percentages always produce amounts within the transaction total (as long as they do not sum above 100).
For most multi-party marketplaces, percentage type is safer and more flexible. Use flat type only when each party's share is a known fixed amount regardless of transaction size.
Creating Split Groups Dynamically Per Order
In theory, split groups are reusable. In practice, most multi-party platforms create a new split group for each order because the participant combination changes every time. A food delivery order at restaurant A with rider B is a different split than restaurant A with rider C.
// Full checkout flow with dynamic split group creation
async function processDeliveryCheckout(order) {
var restaurant = await db.restaurants.findById(order.restaurantId);
var rider = await db.riders.findById(order.riderId);
// Create a split group specific to this order
var splitResponse = await fetch('https://api.paystack.co/split', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Order ' + order.id,
type: 'percentage',
currency: 'NGN',
subaccounts: [
{
subaccount: restaurant.paystackSubaccountCode,
share: restaurant.splitPercentage || 65,
},
{
subaccount: rider.paystackSubaccountCode,
share: 15,
},
],
bearer_type: 'account',
bearer_subaccount: '',
}),
});
var splitData = await splitResponse.json();
if (!splitData.status) {
throw new Error('Could not create split for order: ' + splitData.message);
}
// Store the split code on the order for reconciliation
await db.orders.update(order.id, {
paystackSplitCode: splitData.data.split_code,
});
// Initialize the transaction with the new split code
var txResponse = await fetch('https://api.paystack.co/transaction/initialize', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: order.customerEmail,
amount: order.totalInKobo,
split_code: splitData.data.split_code,
reference: 'delivery_' + order.id + '_' + Date.now(),
}),
});
var txData = await txResponse.json();
return txData.data.authorization_url;
}
This adds one extra API call per checkout (creating the split group). For most platforms, that latency is acceptable since it happens before redirecting the customer to the payment page, not during the payment itself. If the extra call concerns you, consider pre-creating split groups when orders are placed (rather than at checkout) or caching split groups for common participant combinations.
Adding and Removing Subaccounts from a Split Group
Paystack lets you modify existing split groups by adding or removing subaccounts. This is useful for long-running split configurations that evolve over time, like a partnership structure where a new partner joins or an existing one leaves.
// Add a subaccount to an existing split group
async function addToSplitGroup(splitId, subaccountCode, share) {
var response = await fetch(
'https://api.paystack.co/split/' + splitId + '/subaccount/add',
{
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
subaccount: subaccountCode,
share: share,
}),
}
);
return await response.json();
}
// Remove a subaccount from a split group
async function removeFromSplitGroup(splitId, subaccountCode) {
var response = await fetch(
'https://api.paystack.co/split/' + splitId + '/subaccount/remove',
{
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
subaccount: subaccountCode,
}),
}
);
return await response.json();
}
When you add a subaccount, the new share comes out of the residual (your main account's portion). When you remove one, their share goes back to the residual. Make sure the total shares after modification still make sense for your business model.
Changes to a split group affect all future transactions that use its split_code. Transactions that were already processed with the old configuration are not affected. If you need to preserve the old configuration for audit purposes, create a new split group instead of modifying the existing one.
Edge Cases and Gotchas
Multi-split introduces complexity that single split does not have. These are the edge cases that cause problems in production.
Rounding on percentage splits. When a percentage split produces a fractional amount (65% of 9,999 kobo = 6,499.35 kobo), Paystack rounds to the nearest whole unit. Over many transactions, rounding can create small discrepancies between your expected totals and actual settlements. Track these and reconcile periodically rather than investigating each one.
Sum of shares exceeding 100%. If your subaccount percentages add up to more than 100%, Paystack will reject the split group creation. Always validate the total before sending the request.
Flat shares exceeding transaction amount. If you use flat type and the sum of flat shares is greater than the transaction amount, the split cannot be fulfilled. Validate this on your server before initializing the transaction.
Rider not yet assigned. In food delivery, the customer might pay before a rider is assigned. You cannot create the multi-split without the rider's subaccount. Options: use a single split to the restaurant at checkout, then transfer the rider's share later via Paystack Transfers when the rider is assigned. Or, collect the full amount and use transfers for both restaurant and rider. The choice depends on your operational flow.
Refunds on multi-split transactions. Refunding a multi-split transaction refunds from your main Paystack balance. The subaccounts are not automatically debited for their shares. If the restaurant and rider have already been settled, you absorb the full refund amount and recover from them separately.
Split group limits. Paystack does not publicly document a hard limit on subaccounts per split group. In practice, multi-splits with 2 to 5 subaccounts are common. If you need to split among many more parties, test thoroughly and consider whether a different architecture (collect then transfer) might be more appropriate.
For the full context of how multi-split fits into marketplace payment architecture, see the Paystack split payments and marketplaces complete guide.
Key Takeaways
- ✓Multi-split divides one payment among your main account and two or more subaccounts. Use it when a transaction touches three or more parties like a food delivery order (restaurant, rider, platform).
- ✓You create a Transaction Split object with POST /split, specifying the subaccounts and their shares. Paystack returns a split_code that you pass when initializing transactions.
- ✓Shares can be percentages or flat amounts. With percentage type, each subaccount gets X% and your account gets the residual. With flat type, each subaccount gets a fixed amount and your account gets what remains.
- ✓Split groups are reusable but often created per order in practice, since the participant combination (which subaccounts and what shares) changes with every order.
- ✓You can add or remove subaccounts from an existing split group using dedicated endpoints. This is useful for long-running split configurations that evolve over time.
- ✓The bearer_type on a split group controls who absorbs the Paystack processing fee, just like the bearer parameter on single splits.
Frequently Asked Questions
- Can I mix percentage and flat shares in one multi-split group?
- No. The split group type (percentage or flat) applies to all subaccounts in the group. All shares are interpreted the same way. If you need different models for different parties, you would need to calculate the amounts yourself and use flat type with pre-computed values.
- How many subaccounts can I include in one multi-split group?
- Paystack does not publicly state a maximum number of subaccounts per split group. In practice, 2 to 5 subaccounts per group is common. If you need more, test your specific configuration and consider reaching out to Paystack support for guidance on your use case.
- Can I reuse the same split group for different transaction amounts?
- Yes, if the group uses percentage type. The percentages scale with the transaction amount. With flat type, reuse only works if the flat amounts make sense for all possible transaction amounts. If the flat shares could exceed a small transaction amount, you should create a new split group per order.
- What happens to my share if the subaccount percentages add up to 100?
- Your main account gets 0% of the transaction. This is valid but unusual. Paystack still processes the transaction and settles each subaccount their full share. You earn nothing from the split itself. You would only do this if you are monetizing through a separate fee (like a subscription or listing fee) rather than a per-transaction commission.
- Can I use multi-split with recurring charges or subscriptions?
- Split parameters including split_code can be passed during subscription or plan-based charges if the API supports it. Check the current Paystack documentation for subscription splits, as the available parameters and behavior may differ from one-off transactions.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon