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. Build a Referral Payout System
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Build a Referral Payout System

Build a referral payout system by generating unique referral codes per user, tracking conversions when referred users complete a paid action, crediting the referring user's balance with a commission, and paying out via Paystack Transfers when they request a withdrawal. Never pay referral earnings automatically — hold in a pending balance and pay on explicit request.

In this article

  1. 1. Referral Tracking and Commission Logic
  2. 2. Withdrawal Request and Transfer
  3. 3. Learn More

Referral Tracking and Commission Logic

Tables: users (id, email, referral_code, referred_by, pending_balance, paid_balance), referrals (referrer_id, referred_id, status, commission_amount, paid_at), withdrawals (user_id, amount, status, paystack_transfer_ref, requested_at).

// Generate unique referral code on signup
function generateReferralCode(userId) {
  return 'REF-' + userId.toString(36).toUpperCase() + '-' + Math.random().toString(36).slice(2, 6).toUpperCase();
}

// When a referred user registers
async function handleReferralSignup(newUserId, referralCode) {
  var referrer = await db.users.findByReferralCode(referralCode);
  if (!referrer) return;

  await db.referrals.create({
    referrer_id: referrer.id,
    referred_id: newUserId,
    status: 'signed_up', // only credits commission after first payment
  });
  await db.users.update(newUserId, { referred_by: referrer.id });
}

// Webhook: when referred user makes their first payment, credit commission
if (event.event === 'charge.success') {
  var payingUserId = event.data.metadata.user_id;
  var referral = await db.referrals.findPendingByReferredId(payingUserId);

  if (referral && referral.status === 'signed_up') {
    var commission = Math.floor(event.data.amount * 0.1); // 10% commission

    await db.referrals.update(referral.id, { status: 'converted', commission_amount: commission });
    await db.users.increment(referral.referrer_id, 'pending_balance', commission);
    await notifyReferrer(referral.referrer_id, commission);
  }
}

Withdrawal Request and Transfer

async function requestWithdrawal(userId, amount, bankDetails) {
  var user = await db.users.findById(userId);
  var minWithdrawal = 500000; // NGN 5,000 in kobo

  if (amount < minWithdrawal) throw new Error('Minimum withdrawal is NGN 5,000');
  if (amount > user.pending_balance) throw new Error('Insufficient balance');

  // Register recipient if not already done
  if (!user.paystack_recipient_code) {
    var recRes = await fetch('https://api.paystack.co/transferrecipient', {
      method: 'POST',
      headers: { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY, 'Content-Type': 'application/json' },
      body: JSON.stringify({ type: 'nuban', name: bankDetails.name, account_number: bankDetails.account, bank_code: bankDetails.bank_code, currency: 'NGN' }),
    });
    var recData = await recRes.json();
    await db.users.update(userId, { paystack_recipient_code: recData.data.recipient_code });
    user.paystack_recipient_code = recData.data.recipient_code;
  }

  // Deduct from balance immediately (prevent double withdrawal)
  await db.users.decrement(userId, 'pending_balance', amount);

  // Initiate transfer
  var res = await fetch('https://api.paystack.co/transfer', {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ source: 'balance', amount, recipient: user.paystack_recipient_code, reason: 'Referral payout' }),
  });
  var transfer = await res.json();

  await db.withdrawals.create({ user_id: userId, amount, status: 'processing', paystack_transfer_ref: transfer.data.reference });
}

// Webhook: handle transfer outcome
if (event.event === 'transfer.success') {
  await db.withdrawals.update({ ref: event.data.reference }, { status: 'completed' });
  await db.users.increment(event.data.metadata.user_id, 'paid_balance', event.data.amount);
}
if (event.event === 'transfer.failed') {
  // Restore balance on failure
  await db.users.increment(event.data.metadata.user_id, 'pending_balance', event.data.amount);
  await db.withdrawals.update({ ref: event.data.reference }, { status: 'failed' });
  await notifyUserOfFailedWithdrawal(event.data.metadata.user_id);
}

Get weekly developer tips

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

No spam. Unsubscribe anytime.

Learn More

See build an affiliate commission engine for a more detailed affiliate tracking system with conversion attribution.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓Track referrals with a unique code per user, not a shared link — unique codes prevent fraud.
  • ✓Credit commissions to a pending_balance only after the referred user's payment clears (webhook-driven).
  • ✓Pay out via Paystack Transfers on explicit withdrawal request — not automatically.
  • ✓Implement a minimum withdrawal threshold (NGN 5,000) to reduce small transfer fees.
  • ✓Handle transfer.failed webhooks — retry or notify the user to update their bank details.

Frequently Asked Questions

How do I prevent referral fraud (users creating fake accounts)?
Only credit commissions after the referred user makes a real payment via Paystack (not just after signup). Add velocity limits — flag if a single referrer converts more than 5 referrals per day. Require phone number verification on signup. Consider a 30-day hold before commissions can be withdrawn, giving time to detect and reverse fraudulent activity.
Should I pay commissions on recurring revenue or just the first purchase?
Most referral programs pay on the first purchase only (simple and clear). Recurring commission (earning 5% on every purchase the referred user makes) requires more complex tracking but creates stronger incentives for high-value referrers. Decide based on your customer LTV — if customers spend consistently over time, recurring commissions make sense.
What taxes apply to referral income in Nigeria or Kenya?
Referral commissions are income and may be subject to personal income tax (PIT) or withholding tax in Nigeria and Kenya. In Nigeria, withholding tax (WHT) of 5% may apply on commissions paid to individuals. In Kenya, withholding tax may apply depending on the amount and recipient's tax status. Consult a tax advisor — this is not legal or tax advice.

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

Things You Can Build with Paystack: Project Guides

A complete map of real-world projects you can build using the Paystack API. From online store checkouts and subscription platforms to savings apps and solar pay-as-you-go systems, each category links to step-by-step build guides with working code.

Read more

Build a Parking Payment App

A build guide for a parking payment app where drivers scan a QR code on entry, pay for their session via Paystack (card or M-Pesa), and the system validates payment before the barrier lifts for exit. Covers time-based pricing, session management, and overstay handling.

Read more

Build an Affiliate Commission Engine

A build guide for an affiliate commission engine where affiliates share tracking links, earn commissions when their referrals convert (pay via Paystack), and withdraw their balance via bank transfer. Covers click tracking, last-click attribution, commission ledger, and Paystack Transfers payout.

Read more

Build a Farmers Market Ordering Platform

A build guide for a farmers market ordering platform where customers order fresh produce from multiple farmers in one cart, the platform collects the combined payment via Paystack, and each farmer receives their share via Paystack Split Payments or Transfers. Covers inventory management, order routing to individual farmers, and delivery coordination.

Read more

Building a Church or Mosque Contributions Platform

A practical guide to building a digital contributions platform for Kenyan religious institutions. Covers tithe, offering, and zakat collection via M-Pesa and card. Member registration, recurring giving for monthly pledges, campaign fundraising, contribution statements, anonymous donations, multiple fund allocation, and annual financial reports.

Read more

Testing Split Payment Logic Safely

Split payment bugs are expensive — wrong commission rates or incorrect subaccount amounts mean vendors get overpaid or underpaid. This guide covers unit testing commission math, integration testing with Paystack test mode subaccounts, and verifying the full flow end-to-end without touching production.

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.