To onboard a seller to a Paystack marketplace, collect their business name and bank details, validate the account using the Resolve Account endpoint (GET /bank/resolve), show the resolved account name for confirmation, then create a subaccount with POST /subaccount. Store the returned subaccount_code in your database alongside the seller record.
Seller onboarding is the most critical step in building a Paystack marketplace. If a seller cannot receive payments, they cannot sell on your platform. And the bank detail collection process is where most onboarding friction lives.
The challenges:
A good onboarding flow handles all of these. It guides the seller through bank selection, account validation, and confirmation in three clear steps, with graceful error handling at each point.
Start by fetching the list of banks for the seller's country. Paystack returns bank names and codes, which you present as a searchable dropdown or list.
// Fetch banks for the seller's country
async function getBanks(country) {
var response = await fetch(
'https://api.paystack.co/bank?country=' + (country || 'nigeria'),
{
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
},
}
);
var data = await response.json();
if (data.status) {
// Return bank name and code for the dropdown
return data.data.map(function(bank) {
return {
name: bank.name,
code: bank.code,
};
});
}
return [];
}
UI tips for the bank selection step:
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
After the seller selects their bank, collect the account number and validate it using the Resolve Account endpoint. This tells you whether the account exists and returns the name registered on the account.
// Validate the account number against the selected bank
async function validateBankAccount(accountNumber, bankCode) {
var response = await fetch(
'https://api.paystack.co/bank/resolve?account_number=' +
accountNumber +
'&bank_code=' +
bankCode,
{
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
},
}
);
var data = await response.json();
if (data.status) {
return {
valid: true,
accountName: data.data.account_name,
accountNumber: data.data.account_number,
};
}
// Parse the error to give the seller a useful message
var errorMessage = 'We could not verify this account. ';
if (data.message && data.message.includes('Could not resolve')) {
errorMessage = errorMessage + 'Please check that the account number is correct and matches the bank you selected.';
} else {
errorMessage = errorMessage + 'Please try again or contact support.';
}
return {
valid: false,
error: errorMessage,
};
}
Once validation succeeds, show the account name to the seller: "This account is registered to MAMA NJERI KITCHEN. Is this correct?" Give them a clear "Yes, continue" and "No, let me re-enter" option. This confirmation step prevents the most common onboarding error: a correct-looking account number that belongs to someone else.
Handle validation failures with specific guidance:
After the seller confirms their bank details, create the Paystack subaccount. This is the step that links the seller to Paystack's settlement system.
// Create the subaccount after validation and confirmation
async function createSellerSubaccount(seller, bankCode, accountNumber) {
var response = await fetch('https://api.paystack.co/subaccount', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
business_name: seller.shopName || seller.fullName,
settlement_bank: bankCode,
account_number: accountNumber,
percentage_charge: 80,
description: seller.shopName + ' - Seller on ' + process.env.PLATFORM_NAME,
primary_contact_email: seller.email,
primary_contact_phone: seller.phone || '',
metadata: JSON.stringify({
seller_id: seller.id,
platform: process.env.PLATFORM_NAME,
}),
}),
});
var data = await response.json();
if (data.status) {
// Store the subaccount code immediately
await db.sellers.update(seller.id, {
paystackSubaccountCode: data.data.subaccount_code,
paystackSubaccountId: data.data.id,
onboardingStatus: 'complete',
bankCode: bankCode,
accountNumber: accountNumber,
});
return { success: true, subaccountCode: data.data.subaccount_code };
}
// Handle specific creation errors
var errorMessage = 'We could not set up your payment account. ';
if (data.message && data.message.includes('already exists')) {
errorMessage = 'A payment account with these bank details already exists. If you previously registered, please contact support.';
} else {
errorMessage = errorMessage + data.message;
}
return { success: false, error: errorMessage };
}
The creation call can fail even after successful validation. Common reasons:
Every step in the onboarding flow can fail. Good error handling means the seller always knows what went wrong and what to do next.
// Complete onboarding flow with comprehensive error handling
async function fullOnboardingFlow(seller, bankCode, accountNumber) {
// Step 1: Validate
var validation;
try {
validation = await validateBankAccount(accountNumber, bankCode);
} catch (err) {
return {
step: 'validation',
error: 'We could not connect to our payment provider. Please check your internet and try again.',
};
}
if (!validation.valid) {
return {
step: 'validation',
error: validation.error,
retryable: true,
};
}
// Step 2: Confirm with seller (handled by UI)
// The UI shows validation.accountName and waits for confirmation
// Step 3: Create subaccount
var creation;
try {
creation = await createSellerSubaccount(seller, bankCode, accountNumber);
} catch (err) {
return {
step: 'creation',
error: 'Something went wrong while setting up your payment account. Our team has been notified. Please try again in a few minutes.',
};
}
if (!creation.success) {
return {
step: 'creation',
error: creation.error,
retryable: true,
};
}
return {
step: 'complete',
accountName: validation.accountName,
subaccountCode: creation.subaccountCode,
};
}
Error handling principles for onboarding:
The onboarding UI is the seller's first impression of your payment system. It needs to feel trustworthy and be dead simple to use.
Multi-step form pattern. Break the flow into three visible steps: Select Bank, Enter Account Number, and Confirm Details. Show a progress indicator so the seller knows where they are. Each step has one action, one possible failure, and one success path.
Step 1 screen: A searchable dropdown of banks. One input, one button ("Continue"). If the bank list fails to load, show a retry button and a message explaining that you are connecting to the payment provider.
Step 2 screen: An account number input field with the selected bank name shown above it. Validate the length on the frontend (10 digits for Nigeria) before enabling the "Verify" button. Show a loading state while the Resolve Account API call runs.
Step 3 screen: Show the resolved account name in a highlighted box: "Your account is registered to MAMA NJERI KITCHEN." Two buttons: "Yes, this is correct" and "No, let me re-enter." If they confirm, show a loading state while the subaccount is created, then show a success screen.
Success screen: "Your payment account is set up. You can now receive payments from customers." This screen should feel like a milestone. The seller just completed the most important step in joining your marketplace.
Trust signals. Throughout the flow, include text that explains why you need bank details ("So we can pay you directly for your sales"), that money goes straight to their bank ("Paystack sends your earnings directly to your account"), and that their details are secure ("Your bank details are encrypted and handled by Paystack, a licensed payment provider").
For some marketplaces, verifying the seller's identity before allowing them to receive payments is necessary. This is especially important for higher-risk categories (financial services, luxury goods, professional services) or for regulatory compliance.
Paystack offers identity verification endpoints that can verify BVN (Bank Verification Number) in Nigeria and similar identity numbers in other markets. You can also use third-party KYC providers like Smile Identity, Prembly, or Dojah.
Deciding when to add KYC to your onboarding flow:
If you add KYC, make it a separate step from bank onboarding. Sellers should be able to set up their bank details first (the step they understand and expect) and then complete identity verification (the step that feels more invasive) as a follow-up. Combining them into one long form increases abandonment.
For the broader marketplace architecture including checkout, webhooks, and refund handling, see building a two-sided marketplace on Paystack.
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