McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Validating a Customer Before Payout
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 20, 2026

Validating a Customer Before Payout

Before initiating a Paystack transfer, resolve the recipient bank account to confirm it exists and get the registered name. Compare that name against what the user provided using fuzzy matching. For high-value payouts, verify BVN through the Validate Customer endpoint. Enforce daily and per-transaction limits. Only create a transfer recipient and initiate the transfer after all checks pass.

In this article

  1. 1. Why Pre-Payout Validation Matters
  2. 2. Step 1: Resolve the Account Number
  3. 3. Step 2: Match the Name
  4. 4. Step 3: Enforce Payout Limits
  5. 5. Step 4: BVN Verification for High-Value Payouts
  6. 6. Step 5: Create the Transfer Recipient
  7. 7. The First-Payout Hold Period
  8. 8. Building an Audit Trail

Why Pre-Payout Validation Matters

A payout is a push transaction. Once the money leaves your Paystack balance and reaches the recipient's bank account, getting it back requires the recipient's cooperation. Banks can attempt a reversal, but there is no guarantee.

The most common payout mistakes are:

  • Wrong account number. A user mistypes one digit. The money goes to a stranger. You now need that stranger to voluntarily return it.
  • Social engineering. A fraudster convinces your support team to change payout details. The next payout goes to the fraudster's account.
  • Account takeover. Someone gains access to a user's account on your platform and changes the payout bank details to their own.
  • Duplicate payouts. A bug or retry logic sends the same payout twice.

Pre-payout validation catches all of these. It adds a few seconds to the payout process and saves you from losses that can be difficult or impossible to reverse.

Step 1: Resolve the Account Number

The first check is always account resolution. Before you do anything else, confirm that the bank account exists and get the name on it.

// validate-payout.js
const axios = require('axios');

async function resolveAccount(accountNumber, bankCode) {
  var response = await axios.get(
    'https://api.paystack.co/bank/resolve',
    {
      params: {
        account_number: accountNumber,
        bank_code: bankCode,
      },
      headers: {
        Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      },
      timeout: 15000,
    }
  );

  return response.data.data;
}

If resolution fails (422): The account does not exist at that bank. Stop immediately. Do not proceed with the payout. Tell the user their bank details could not be verified and ask them to re-enter.

If resolution times out: Do not proceed. African bank systems can be slow, but an unresolved account is an unverified account. Retry after a short delay. If it times out three times, tell the user to try again later.

For detailed error handling on this endpoint, see the Resolve Account Number guide.

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Step 2: Match the Name

You now have the bank's registered account name. Compare it with the name your user provided during registration or payout setup.

This comparison is harder than it sounds. Banks format names differently:

  • One bank returns "OKAFOR JOHN DOE"
  • Another returns "John Doe Okafor"
  • Another returns "JOHN D. OKAFOR"

Exact string comparison will reject all of these as mismatches even when they refer to the same person.

// name-match.js
function normalizeNameParts(name) {
  return name
    .toUpperCase()
    .replace(/[^A-Z\s]/g, '')
    .split(/\s+/)
    .filter(function(part) { return part.length > 1; })
    .sort();
}

function namesMatch(name1, name2) {
  var parts1 = normalizeNameParts(name1);
  var parts2 = normalizeNameParts(name2);

  // Count how many name parts overlap
  var matches = 0;
  parts1.forEach(function(part) {
    if (parts2.indexOf(part) !== -1) {
      matches++;
    }
  });

  // Require at least 2 matching parts (first name + last name)
  var minParts = Math.min(parts1.length, parts2.length);
  return matches >= Math.min(2, minParts);
}

What to do on mismatch: Show the user the resolved name and ask: "The bank account is registered to [name]. Is this your account?" Let them confirm or re-enter. Do not automatically reject the payout. Women who recently married, people with multiple legal names, and people who use shortened versions of their name are all legitimate.

For a deeper treatment of name matching, see the fuzzy comparison guide.

Step 3: Enforce Payout Limits

Even if the account resolves and the name matches, you should enforce limits before sending money.

// payout-limits.js
async function checkPayoutLimits(userId, amount) {
  var errors = [];

  // Per-transaction limit
  var maxPerTransaction = 500000 * 100; // 500,000 NGN in kobo
  if (amount > maxPerTransaction) {
    errors.push('Amount exceeds per-transaction limit');
  }

  // Daily limit
  var todayTotal = await db.query(
    'SELECT COALESCE(SUM(amount), 0) as total FROM payouts ' +
    'WHERE user_id = $1 AND status = $2 AND created_at > NOW() - INTERVAL '24 hours'',
    [userId, 'success']
  );

  var dailyLimit = 2000000 * 100; // 2,000,000 NGN in kobo
  if (todayTotal.rows[0].total + amount > dailyLimit) {
    errors.push('Would exceed daily payout limit');
  }

  // Velocity check: max 5 payouts per hour
  var recentCount = await db.query(
    'SELECT COUNT(*) as count FROM payouts ' +
    'WHERE user_id = $1 AND created_at > NOW() - INTERVAL '1 hour'',
    [userId]
  );

  if (parseInt(recentCount.rows[0].count) >= 5) {
    errors.push('Too many payouts in the last hour');
  }

  return { allowed: errors.length === 0, errors: errors };
}

Set limits based on your risk appetite. A payroll product sending salaries once a month has different limits than a marketplace sending daily settlements. Start conservative and increase limits as you gain confidence in your users.

Tiered limits. New users get lower limits. Users who have completed BVN verification get higher limits. Users with a long transaction history get the highest limits. This rewards trust without exposing you to risk from unverified accounts.

Step 4: BVN Verification for High-Value Payouts

For payouts above a threshold you define, require BVN verification before proceeding. This adds a second layer of identity confirmation beyond account resolution.

// high-value-check.js
var HIGH_VALUE_THRESHOLD = 100000 * 100; // 100,000 NGN in kobo

async function requiresEnhancedVerification(userId, amount) {
  if (amount < HIGH_VALUE_THRESHOLD) {
    return false;
  }

  // Check if user is already BVN-verified
  var verification = await db.query(
    'SELECT verified FROM identity_verifications ' +
    'WHERE user_id = $1 AND verification_type = $2 AND verified = true',
    [userId, 'bvn']
  );

  if (verification.rows.length > 0) {
    return false; // Already verified, no need to re-verify
  }

  return true; // Needs BVN verification before this payout
}

When to trigger BVN verification: Before the first high-value payout, not during it. If a user is setting up their payout details, run BVN verification as part of the setup. Do not wait until they request a large payout. That creates friction at the worst moment.

For full BVN verification implementation, see the BVN verification guide.

Step 5: Create the Transfer Recipient

Only after all validation passes should you create a transfer recipient in Paystack.

// create-recipient.js
async function createTransferRecipient(name, accountNumber, bankCode) {
  var response = await axios.post(
    'https://api.paystack.co/transferrecipient',
    {
      type: 'nuban',
      name: name,
      account_number: accountNumber,
      bank_code: bankCode,
      currency: 'NGN',
    },
    {
      headers: {
        Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
        'Content-Type': 'application/json',
      },
    }
  );

  return response.data.data;
}

Store the recipient code. Save the recipient_code in your database linked to the user. For future payouts to the same account, reuse the recipient code instead of creating a new one.

Re-validate on changes. If a user changes their bank details, do not just update the existing recipient. Delete the old one, run the full validation again (resolve, name match, limits), and create a new recipient only after everything passes.

The First-Payout Hold Period

Consider holding the first payout to a new bank account for 24 hours before releasing it. This gives you time to catch fraud that automated checks miss.

How it works:

  1. User requests a payout to a new bank account.
  2. All automated checks pass (resolution, name match, limits).
  3. You create the payout record with status "pending_review" instead of initiating it immediately.
  4. After 24 hours, a background job checks if the user's account shows any suspicious activity (login from new IP, sudden profile changes, customer complaints).
  5. If everything looks clean, initiate the transfer.

Communicate clearly. Tell the user upfront: "First payouts to new bank accounts take up to 24 hours for security verification. Subsequent payouts to the same account process immediately." Users accept this when they understand it protects their money.

Skip the hold for verified users. If a user has completed BVN verification and has a history of successful payouts, skip the hold period. Reward trust.

Building an Audit Trail

Log every step of the validation process. When a dispute arises weeks later, your logs are your evidence.

// audit-log.js
async function logValidationStep(payoutId, step, result, details) {
  await db.query(
    'INSERT INTO payout_audit_log (payout_id, step, result, details, created_at) ' +
    'VALUES ($1, $2, $3, $4, NOW())',
    [payoutId, step, result, JSON.stringify(details)]
  );
}

// Usage throughout the validation flow
await logValidationStep(payoutId, 'account_resolution', 'success', {
  account_name: 'OKAFOR JOHN DOE',
  bank_code: '058',
});

await logValidationStep(payoutId, 'name_match', 'pass', {
  user_name: 'John Okafor',
  resolved_name: 'OKAFOR JOHN DOE',
  match_score: 0.85,
});

await logValidationStep(payoutId, 'limit_check', 'pass', {
  amount: 5000000,
  daily_total: 12000000,
  daily_limit: 200000000,
});

What to log: The resolved account name, the name comparison result (including both names and the match score), the limit check results, whether BVN verification was required and what the outcome was, and the final decision (approved or rejected).

Retention. Keep payout audit logs for at least 2 years. Regulatory requirements in Nigeria and Kenya may require longer. Check with your legal team.

Key Takeaways

  • ✓Always resolve the account number before creating a transfer recipient. This confirms the account exists and gives you the registered name.
  • ✓Use fuzzy name matching, not exact string comparison, to compare the resolved name with the user-provided name. Banks format names differently.
  • ✓Enforce payout limits at the application level. Set per-transaction maximums, daily ceilings, and velocity limits that match your risk appetite.
  • ✓For high-value payouts, require BVN verification in addition to account resolution. Two verification points are stronger than one.
  • ✓Log every validation step with timestamps. When disputes arise, your logs prove you did due diligence before sending the money.
  • ✓Build a hold period for first-time recipients. The first payout to a new bank account can wait 24 hours. Fraud rarely survives a cooling-off period.

Frequently Asked Questions

Can I skip account resolution and just create a transfer recipient directly?
Technically yes, but you should not. Creating a transfer recipient without resolving the account first means you have no idea if the account exists or who owns it. If the account number is wrong, the transfer will fail. If it is right but belongs to someone else, you just sent money to a stranger.
How do I handle a user who changes their bank details frequently?
Frequent bank detail changes are a fraud signal. Implement a cooldown period: after changing bank details, the user cannot request a payout for 24 to 48 hours. Run the full validation flow each time details change. If changes happen more than twice in a month, flag the account for manual review.
What payout limits should I start with?
Start conservative. A reasonable starting point for a new product is a per-transaction limit that matches your typical transaction size and a daily limit that is 3 to 5 times that. Increase limits as you gain confidence in your fraud detection and user verification. Every business is different, so adjust based on your actual risk experience.
Should I validate the recipient every time or just the first time?
Resolve the account at least on the first payout to a new bank account and whenever the user changes their bank details. For repeat payouts to the same verified account, you can skip resolution and reuse the stored transfer recipient code. Re-validate periodically, perhaps monthly, to catch accounts that have been closed.

Learn Paystack Integration

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

Not ready? Create Free Account

Keep reading

Paystack Identity Verification: Complete Guide

Paystack gives you three identity endpoints: resolve account number, resolve card BIN, and validate customer (BVN). This guide shows you how to use each one, build a KYC flow around them, and stay within the Kenya DPA and Nigeria NDPR while doing it.

Read more

Resolve Card BIN: What It Tells You and What It Does Not

The Resolve Card BIN endpoint takes the first six digits of a card number and tells you the card brand, issuing bank, type, and country. It is useful for fraud screening, UX polish, and routing decisions. But it does not tell you who owns the card, whether it has funds, or whether a charge will succeed.

Read more

Account Name Matching and Fuzzy Comparison

Banks return names in unpredictable formats. "OKAFOR JOHN DOE" and "John Okafor" are the same person, but a strict string comparison says they are different. This guide shows you how to build a fuzzy name matching system that handles real-world African name formats without blocking legitimate users.

Read more

Rate Limits and Caching for Identity Lookups

Paystack rate-limits identity endpoints to prevent abuse. If you call Resolve Account Number on every page load or every form submission, you will hit the limit and your verifications will fail. This guide shows you how to cache results properly, throttle requests, and build an identity lookup layer that stays fast even under heavy traffic.

Read more

Role Based Access for Payment Operations Teams

Not everyone on your team needs access to payment data, API keys, or transfer endpoints. Poorly scoped access is one of the most common causes of internal payment fraud and data leaks. This guide covers role-based access control for teams operating a Paystack integration.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.