Bonaventure OgetoBy Bonaventure Ogeto|

Onboarding Sellers to a Paystack Marketplace

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.

The Onboarding Problem

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:

  • Sellers enter wrong account numbers. A transposed digit means settlements go to the wrong person or fail entirely. You need to validate before committing.
  • Sellers do not know their bank code. They know "First Bank" but not that the code is "011." You need to present a searchable list.
  • Sellers distrust the process. Entering bank details into a website feels risky. Your UI needs to communicate safety and explain why you need the information.
  • Failure modes are confusing. A "subaccount creation failed" error from Paystack means nothing to a seller. You need to translate every error into plain language with a clear next step.

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.

Step 1: Bank Selection

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:

  • Make the dropdown searchable. Nigeria alone has dozens of banks. Scrolling through a list is frustrating. Let sellers type "GT" and see "GTBank" immediately.
  • Cache the bank list. It does not change frequently. Fetch it once when the onboarding page loads (or cache it server-side) rather than calling the API on every keystroke.
  • Support the seller's country. Pass the right country parameter: "nigeria", "kenya", "ghana", or "south_africa". If your marketplace operates in multiple countries, detect the country from the seller's profile or let them select it.
  • Show the full bank name, not the code. The code is an internal identifier. Sellers need to see "Guaranty Trust Bank" not "058."

Step 2: Account Number Validation

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:

  • "Could not resolve account": The account number does not match any account at the selected bank. Ask the seller to double-check both the number and the bank.
  • Network timeout: The request to Paystack timed out. Show "We could not reach our payment provider. Please try again in a moment."
  • Account number format: Nigerian accounts are 10 digits. Validate the length on the frontend before sending the API call.

Step 3: Subaccount Creation

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:

  • Duplicate subaccount: Another subaccount with the same bank details already exists on your Paystack account. This happens if the seller previously onboarded or if two sellers share a bank account (which you should probably not allow).
  • API rate limiting: If you are onboarding many sellers at once, you might hit Paystack's rate limits. Implement retry logic with exponential backoff.
  • Invalid business name: Paystack may reject certain characters or lengths in the business name. Sanitize the input before sending.

Error Handling Across the Flow

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:

  • Never show raw API errors to sellers. "SubaccountCreationError: BANK_CODE_INVALID" means nothing to a shop owner. Translate every error into plain language.
  • Tell the seller what to do next. "Please check your account number" is better than "Invalid account." "Please try again in a few minutes" is better than "Server error."
  • Log everything. Even if you show a friendly message to the seller, log the raw error with the seller ID and bank details (minus the full account number for security) so your support team can investigate.
  • Make retries easy. Pre-fill the bank selection and account number so the seller does not have to re-enter everything after a failure.

Onboarding UI Design

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").

KYC and Identity Verification

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:

  • Low-risk marketplaces (small items, low values): Bank account validation alone is usually sufficient. The bank already performed KYC when the seller opened their account. Adding another KYC step adds friction that reduces seller conversion.
  • Medium-risk marketplaces (services, moderate values): Consider verifying the seller's identity after they complete bank onboarding but before their first settlement. This lets them start listing products while KYC is processed, reducing perceived friction.
  • High-risk marketplaces (high-value goods, financial services): Verify identity before allowing any listings or transactions. The friction is justified by the risk.

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.

Build Production-Ready Onboarding

Seller onboarding is where the marketplace experience begins. Getting it right means sellers trust your platform, set up quickly, and start selling without frustration.

The McTaba bootcamp teaches you to build complete marketplace systems, from seller onboarding to payment processing to deployment. Real integrations, real money, real users.

Create a free McTaba account

Key Takeaways

  • The onboarding flow has three API steps: list banks (GET /bank), resolve account (GET /bank/resolve), and create subaccount (POST /subaccount). Wrap them in a user-friendly multi-step form.
  • Always resolve the bank account before creating the subaccount. Show the resolved account name to the seller and ask for confirmation. This catches wrong account numbers before they cause problems.
  • Handle every failure mode gracefully: wrong bank code, invalid account number, account not found, and API timeout. Each needs a clear, non-technical error message.
  • Store the subaccount_code in your database immediately after creation. This is the key you use in every future split transaction for this seller.
  • Consider adding identity verification (KYC) to the onboarding flow for higher-risk marketplaces. Paystack offers verification endpoints, or you can use a third-party KYC provider.
  • Do not let sellers list products or accept orders until their onboarding is complete. An incomplete onboarding means the checkout will fail when a buyer tries to pay.

Frequently Asked Questions

Should I let sellers onboard without bank details and add them later?
You can let sellers create a profile and list products without bank details, but block checkout for their products until onboarding is complete. This lets sellers explore the platform and prepare their listings while reducing pressure to complete bank details immediately. Show a clear message on their dashboard: "Complete your payment setup to start receiving orders."
What if two sellers have the same bank account number?
This is unusual and potentially a red flag. Two legitimate businesses rarely share one bank account. Paystack may not allow you to create two subaccounts with identical bank details. If you encounter this, investigate before proceeding. It could be a data entry error, a shared family account (common with small businesses), or a sign of fraud.
Can a seller use a personal bank account instead of a business account?
Paystack subaccounts work with both personal and business bank accounts. Many small sellers on African marketplaces use personal accounts. The Resolve Account endpoint will return the name on the account regardless of whether it is personal or business. Whether you require a business account is a policy decision for your platform, not a Paystack constraint.
How do I handle sellers who want to receive payments via mobile money?
Paystack subaccounts settle to bank accounts. If a seller only has mobile money (common in markets like Kenya and Ghana), they would need a bank account for Paystack settlement. Alternatively, you could collect the full payment into your account and use Paystack Transfers or another provider to send the seller's share to their mobile money wallet. This adds complexity but may be necessary for your market.
How long does the onboarding process take from the seller's perspective?
If the seller has their bank details ready, the entire flow takes under two minutes: select bank (10 seconds), enter account number (10 seconds), wait for validation (2-5 seconds), confirm account name (5 seconds), wait for subaccount creation (2-5 seconds). The total API time is under 15 seconds. The rest is the seller reading and clicking.

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