Paystack subaccount settlements go missing for five reasons: the subaccount bank details are wrong or outdated, the settlement schedule has not triggered yet (Paystack settles on a schedule, not instantly), the split was not applied to the transaction, the subaccount was deactivated, or there is an outstanding compliance hold on the account. Check the subaccount status via the API, verify bank details match the account holder, confirm the split was applied to the transaction, and check the settlement schedule in your dashboard.
When a customer pays and a split is applied, Paystack calculates each party's share at the transaction level. But the money does not move to bank accounts immediately. Paystack batches settlements and sends them on a schedule.
Here is the timeline:
When a settlement is "missing," one of these steps failed. Either the share was never calculated (split not applied), the settlement was delayed (schedule not triggered yet), or the bank transfer failed (wrong details, bank issues).
This is the most common cause. The subaccount was created with bank details that are now wrong. Maybe the vendor changed banks, or there was a typo in the original account number, or the bank merged and the bank code changed.
When Paystack tries to settle to an invalid bank account, the transfer fails. The money stays in Paystack's system (it does not disappear), but the subaccount holder does not receive it.
const axios = require('axios');
const headers = {
Authorization: `Bearer ${process.env.PAYSTACK_SECRET_KEY}`,
'Content-Type': 'application/json',
};
// Check current subaccount bank details
async function checkSubaccountBankDetails(subaccountCode) {
const response = await axios.get(
`https://api.paystack.co/subaccount/${subaccountCode}`,
{ headers }
);
const sub = response.data.data;
console.log('Business name:', sub.business_name);
console.log('Bank:', sub.settlement_bank);
console.log('Account number:', sub.account_number);
console.log('Verified:', sub.is_verified);
return sub;
}
// Update bank details if they changed
async function updateSubaccountBankDetails(subaccountCode, newBankCode, newAccountNumber) {
// First, resolve the account to verify it is valid
const resolveResponse = await axios.get(
`https://api.paystack.co/bank/resolve?account_number=${newAccountNumber}&bank_code=${newBankCode}`,
{ headers }
);
console.log('Resolved account name:', resolveResponse.data.data.account_name);
// Update the subaccount
const updateResponse = await axios.put(
`https://api.paystack.co/subaccount/${subaccountCode}`,
{
settlement_bank: newBankCode,
account_number: newAccountNumber,
},
{ headers }
);
console.log('Updated:', updateResponse.data.data.business_name);
console.log('New bank:', updateResponse.data.data.settlement_bank);
console.log('New account:', updateResponse.data.data.account_number);
}
// Example: check and update
checkSubaccountBankDetails('ACCT_xxxxxxxx').catch(console.error);
Always resolve the account number against the bank before updating. The Paystack Bank Resolve API (GET /bank/resolve) confirms that the account number exists at that bank and returns the account holder's name. This prevents typos from causing future settlement failures.
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
Paystack does not settle in real time. The standard settlement schedule is T+1, meaning transactions from Monday settle on Tuesday, Tuesday settles on Wednesday, and so on. But there are important exceptions:
If your vendor says "I was paid on Friday but the money has not arrived," the answer might simply be that settlement happens on Monday.
Check your settlement schedule in the Paystack dashboard under Settings > Settlement. You can also check programmatically:
// Check recent settlements
async function checkSettlements() {
const response = await axios.get(
'https://api.paystack.co/settlement',
{
headers: {
Authorization: `Bearer ${process.env.PAYSTACK_SECRET_KEY}`,
},
params: {
perPage: 10,
},
}
);
const settlements = response.data.data;
for (const settlement of settlements) {
console.log('Settlement ID:', settlement.id);
console.log('Amount:', settlement.total_amount / 100, 'NGN');
console.log('Status:', settlement.status);
console.log('Date:', settlement.settled_date || 'Pending');
console.log('---');
}
}
checkSettlements().catch(console.error);
If the settlement shows as "pending," it has not been sent to the bank yet. This is normal within the settlement window. If it shows as "failed," there is a problem with the bank details or Paystack has flagged the account.
The transaction succeeded, but the split was never applied. The entire amount went to your main account, and the subaccount got nothing. This feels like a "missing settlement" from the vendor's perspective, but it is actually a split configuration issue.
Verify whether the split was applied by checking the transaction:
async function checkTransactionSplit(reference) {
const response = await axios.get(
`https://api.paystack.co/transaction/verify/${reference}`,
{
headers: {
Authorization: `Bearer ${process.env.PAYSTACK_SECRET_KEY}`,
},
}
);
const data = response.data.data;
console.log('Transaction:', reference);
console.log('Status:', data.status);
console.log('Amount:', data.amount / 100, 'NGN');
if (data.split) {
console.log('Split applied: YES');
console.log('Split code:', data.split.split_code);
} else if (data.subaccount) {
console.log('Subaccount transaction: YES');
console.log('Subaccount:', data.subaccount.subaccount_code);
} else {
console.log('Split applied: NO');
console.log('Full amount went to main account.');
console.log('Fix: include split_code when initializing transactions.');
}
}
checkTransactionSplit('REF_xxxxx').catch(console.error);
If the split was not applied, the fix is in your transaction initialization code, not in the subaccount or settlement configuration. See our guide on Paystack Split Not Applied to Transaction for the full troubleshooting process.
Subaccounts can be deactivated for several reasons: you manually deactivated it, Paystack flagged it for compliance, or the bank verification failed. A deactivated subaccount will not receive settlements, even if transactions with its split_code continue to succeed (the money accumulates but does not settle).
// Check if subaccount is active
async function isSubaccountActive(subaccountCode) {
const response = await axios.get(
`https://api.paystack.co/subaccount/${subaccountCode}`,
{
headers: {
Authorization: `Bearer ${process.env.PAYSTACK_SECRET_KEY}`,
},
}
);
const sub = response.data.data;
if (!sub.active) {
console.warn(`Subaccount ${subaccountCode} is INACTIVE.`);
console.warn('Reason: Check Paystack dashboard for details.');
console.warn('Settlements are paused until reactivated.');
return false;
}
console.log(`Subaccount ${subaccountCode} is active.`);
return true;
}
If the subaccount was deactivated by Paystack for compliance reasons, you will need to resolve the issue through the Paystack dashboard or by contacting their support. Common compliance triggers include:
Paystack is regulated by the CBN (Central Bank of Nigeria) and other financial regulators in the countries it operates. Occasionally, settlements are held for compliance review. This is not common, but when it happens, it can freeze settlements for days or weeks.
Signs of a compliance hold:
There is no API to check for compliance holds. You need to log into the Paystack dashboard and look for notifications, or contact Paystack support directly.
To prevent compliance issues:
If you run a marketplace or platform with multiple subaccounts, you will get settlement questions from vendors constantly. Build an internal tool that answers the most common questions without requiring you to log into the Paystack dashboard.
const axios = require('axios');
const headers = {
Authorization: `Bearer ${process.env.PAYSTACK_SECRET_KEY}`,
};
async function getVendorSettlementSummary(subaccountCode) {
// 1. Get subaccount details
const subResponse = await axios.get(
`https://api.paystack.co/subaccount/${subaccountCode}`,
{ headers }
);
const sub = subResponse.data.data;
// 2. Get recent transactions for this subaccount
const txnResponse = await axios.get(
'https://api.paystack.co/transaction',
{
headers,
params: {
subaccount: subaccountCode,
status: 'success',
perPage: 50,
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(), // Last 7 days
},
}
);
const transactions = txnResponse.data.data;
const totalAmount = transactions.reduce((sum, t) => sum + t.amount, 0);
console.log('=== Vendor Settlement Summary ===');
console.log('Business:', sub.business_name);
console.log('Active:', sub.active ? 'Yes' : 'NO - settlements paused');
console.log('Bank:', sub.settlement_bank, sub.account_number);
console.log('Verified:', sub.is_verified ? 'Yes' : 'NO - bank details need verification');
console.log('');
console.log('Last 7 days:');
console.log(' Transactions:', transactions.length);
console.log(' Total amount:', totalAmount / 100, 'NGN');
console.log('');
// 3. List individual transactions
for (const txn of transactions.slice(0, 10)) {
console.log(` ${txn.created_at} - ${txn.amount / 100} NGN - ${txn.reference}`);
}
if (!sub.active) {
console.warn('\nACTION REQUIRED: Subaccount is inactive. Check Paystack dashboard.');
}
if (!sub.is_verified) {
console.warn('\nACTION REQUIRED: Bank details not verified. Update and verify.');
}
}
getVendorSettlementSummary('ACCT_xxxxxxxx').catch(console.error);
Expose this as an internal admin endpoint so your support team can look up any vendor's settlement status in seconds. Add the ability to cross-reference with your own database to spot discrepancies between Paystack records and what you have credited internally.
Vendors who are not receiving money get frustrated quickly. Clear, honest communication makes a big difference.
If the settlement is within the normal window (T+1):
"Settlements are processed on the next business day. If your transaction was yesterday, the settlement will arrive today. Weekend transactions settle on Monday."
If bank details are wrong:
"Your bank details on file do not match a valid account. Please confirm your account number and bank name, and we will update your profile. Once updated, pending settlements will be released."
If the subaccount is inactive:
"Your vendor account is currently on hold. We need [specific documentation or action] to reactivate it. Please [contact support / upload documents / etc]."
If the split was not applied:
"We identified that some recent transactions were processed without the revenue split. We are correcting this and will transfer your share manually. This will arrive within [your SLA]."
For the manual transfer case, use the Paystack Transfer API to send the vendor their share from your main account balance.
After fixing the root cause, confirm everything works end to end.
GET /subaccount/{code}. Confirm active: true and is_verified: true.GET /bank/resolve with the subaccount's bank code and account number. Confirm the account name matches the expected vendor.For any settlements that were missed during the period the subaccount was broken, you may need to manually transfer the funds using the Transfer API. Calculate the total owed by summing the subaccount shares from all affected transactions, and initiate a bulk transfer.
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course