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. Payout Scheduling and Batching Strategies
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 20, 2026

Payout Scheduling and Batching Strategies

Schedule payouts after your settlement cycle completes so funds are available. Batch transfers in groups of up to 100 for the bulk endpoint. Add 2-3 second delays between batches to respect rate limits. Run payouts during business hours for fastest settlement. For large payout runs, split across multiple execution windows to manage risk and rate limits.

In this article

  1. 1. Payout Scheduling Fundamentals
  2. 2. Aligning Payouts with Settlement Cycles
  3. 3. Batching Strategies for Different Models
  4. 4. Rate Limit Management
  5. 5. Choosing Optimal Execution Windows
  6. 6. Building a Production Scheduler
  7. 7. Build Reliable Payout Operations

Payout Scheduling Fundamentals

Paystack does not have a built-in scheduler. All transfers execute immediately when you call the API. Scheduling is your application's responsibility. You decide when to call the API, and you build the logic to determine which payouts are due at each execution time.

The scheduling decision depends on three factors: when your funds are available (settlement cycle), when your recipients expect to be paid (vendor agreements, payroll dates), and when the banking system processes transfers most efficiently (business hours, avoiding maintenance windows).

A simple scheduler uses a cron job that runs at fixed intervals and processes approved payouts. A sophisticated scheduler uses a job queue that handles retries, tracks execution state, and adapts to balance availability.

// Simple cron-based scheduler
// Run every day at 10:00 AM EAT
// crontab: 0 10 * * * node /app/scripts/run-payouts.js

async function scheduledPayoutRun() {
  var today = new Date();
  var dayOfWeek = today.getDay(); // 0=Sunday, 1=Monday, ...

  // Only run on weekdays
  if (dayOfWeek === 0 || dayOfWeek === 6) {
    console.log('Skipping payout run on weekend');
    return;
  }

  console.log('Starting scheduled payout run: ' + today.toISOString());

  var currencies = ['NGN', 'KES', 'GHS'];
  for (var i = 0; i < currencies.length; i++) {
    await executePayoutsForCurrency(currencies[i]);
  }

  console.log('Payout run complete');
}

Aligning Payouts with Settlement Cycles

Your settlement cycle determines when customer payment funds become available for transfers. If you try to run payouts before settlement completes, your available balance may be lower than expected.

T+1 settlement (next business day): Monday's payments are available Tuesday. Schedule vendor payouts for Tuesday's payments on Wednesday or later.

Weekly settlement: Payments from the previous week settle on a specific day. Schedule payouts for the day after settlement.

Build a buffer. Even with T+1, some payments may take slightly longer to settle. Running payouts on Wednesday for Monday's revenue gives you an extra day of buffer and catches any late settlements.

// Determine the safe payout date for a given revenue period
function getSafePayoutDate(revenueEndDate, settlementDays) {
  var payoutDate = new Date(revenueEndDate);

  // Add settlement days
  var daysAdded = 0;
  while (daysAdded < settlementDays + 1) { // +1 for buffer
    payoutDate.setDate(payoutDate.getDate() + 1);
    var day = payoutDate.getDay();
    if (day !== 0 && day !== 6) { // Skip weekends
      daysAdded++;
    }
  }

  return payoutDate;
}

// T+1 settlement, revenue period ends Sunday July 20
var payoutDate = getSafePayoutDate(new Date('2026-07-20'), 1);
// Returns Wednesday July 23 (Mon=T+1, Tue=buffer, Wed=payout)

Get weekly developer tips

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

No spam. Unsubscribe anytime.

Batching Strategies for Different Models

Marketplace vendor payouts (weekly)

Calculate each vendor's earnings for the week, create payout records, batch into groups of 100, and execute on the scheduled day. This is the most common pattern.

Driver/rider settlements (daily)

At the end of each day, calculate each driver's completed trips, deduct the platform commission, and batch the net amounts for transfer. Daily payouts require reliable automation because manual processing every day is not sustainable.

Payroll (monthly)

Process all employee salaries in a single batch run on the designated payroll date. Pre-fund the balance well before the payroll date to avoid surprises. See payroll disbursement with Paystack bulk transfers.

On-demand / instant payouts

No batching. When a vendor requests an instant payout, execute it immediately as a single transfer. This requires OTP to be disabled and a pre-funded balance. Set daily limits per vendor to prevent balance drain.

// Batch assembly for weekly vendor payouts
async function assembleWeeklyBatch(weekEndDate) {
  var vendors = await db.vendors.findActive();
  var payouts = [];

  for (var i = 0; i < vendors.length; i++) {
    var vendor = vendors[i];
    var earnings = await calculateVendorEarnings(vendor.id, weekEndDate);

    if (earnings.netAmount <= 0) continue; // No payout needed

    payouts.push({
      vendorId: vendor.id,
      recipientCode: vendor.paystackRecipientCode,
      amountMinorUnit: earnings.netAmount,
      currency: earnings.currency,
      reason: 'Weekly payout ending ' + weekEndDate,
      reference: 'weekly_' + vendor.id + '_' + weekEndDate,
    });
  }

  return payouts;
}

Rate Limit Management

Paystack enforces rate limits on API calls. If you send too many requests too quickly, you get throttled. Throttled requests return error responses, and your payout run stalls.

For bulk transfers, the main concern is the delay between consecutive batch submissions. Each batch of 100 is a single API call, but if you submit 10 batches back-to-back, that is 10 calls in quick succession.

async function executeWithRateLimiting(batches, currency) {
  var delayBetweenBatches = 3000; // 3 seconds

  for (var i = 0; i < batches.length; i++) {
    console.log(
      'Executing batch ' + (i + 1) + ' of ' + batches.length
      + ' (' + batches[i].length + ' transfers)'
    );

    try {
      await initiateBulkTransfer(currency, batches[i]);
    } catch (err) {
      if (err.message.indexOf('rate') !== -1 || err.message.indexOf('429') !== -1) {
        // Rate limited: wait longer and retry
        console.log('Rate limited. Waiting 30 seconds...');
        await new Promise(function(r) { setTimeout(r, 30000); });

        // Retry this batch
        try {
          await initiateBulkTransfer(currency, batches[i]);
        } catch (retryErr) {
          console.error('Batch ' + (i + 1) + ' failed on retry: ' + retryErr.message);
        }
      } else {
        console.error('Batch ' + (i + 1) + ' failed: ' + err.message);
      }
    }

    // Standard delay between batches
    if (i < batches.length - 1) {
      await new Promise(function(r) { setTimeout(r, delayBetweenBatches); });
    }
  }
}

Three seconds between batches is a safe starting point. If you still hit rate limits, increase to 5 seconds. If you never hit limits, you can try reducing to 2 seconds. Monitor your error rates and adjust.

Choosing Optimal Execution Windows

When you execute payouts affects settlement speed and success rate.

Best: 9 AM - 3 PM local time, weekdays. Banks are fully operational. Interbank clearing runs frequently. Most transfers settle within minutes to a few hours.

Acceptable: 3 PM - 9 PM local time, weekdays. Some banks start batch processing for end of day. Transfers may take longer but generally succeed.

Risky: 9 PM - 6 AM and weekends. Banks run maintenance, batch processing, and reconciliation. Higher chance of transient failures. Transfers may queue until the next business day.

Avoid: Month-end (25th-30th). Banking systems are under heavy load from payroll processing across the entire economy. Higher failure rates and longer settlement times.

M-Pesa and mobile money are exceptions. They operate 24/7 with consistent performance. If your payouts are primarily to M-Pesa wallets, execution timing is less critical.

Building a Production Scheduler

// Job-based scheduler with state tracking
async function createPayoutJob(jobType, currency, executionDate) {
  return await db.payoutJobs.create({
    jobType: jobType, // 'weekly_vendor', 'daily_driver', 'monthly_payroll'
    currency: currency,
    executionDate: executionDate,
    status: 'pending', // pending, running, completed, failed, partial
    totalPayouts: 0,
    completedPayouts: 0,
    failedPayouts: 0,
    createdAt: new Date(),
  });
}

async function runPayoutJob(jobId) {
  var job = await db.payoutJobs.findById(jobId);
  if (job.status !== 'pending') {
    console.log('Job already ' + job.status + '. Skipping.');
    return;
  }

  await db.payoutJobs.update(jobId, { status: 'running', startedAt: new Date() });

  try {
    // Assemble payouts for this job
    var payouts = await assemblePayoutsForJob(job);
    await db.payoutJobs.update(jobId, { totalPayouts: payouts.length });

    if (payouts.length === 0) {
      await db.payoutJobs.update(jobId, {
        status: 'completed',
        completedAt: new Date(),
        note: 'No payouts to process',
      });
      return;
    }

    // Execute with balance check and batching
    await executePayoutBatch(payouts, job.currency, jobId);

    // Final status will be set by the reconciliation check
    await db.payoutJobs.update(jobId, {
      status: 'completed',
      completedAt: new Date(),
    });
  } catch (err) {
    await db.payoutJobs.update(jobId, {
      status: 'failed',
      note: err.message,
    });
    await alertOps('Payout job ' + jobId + ' failed: ' + err.message);
  }
}

Track each payout run as a "job" with its own status. This gives your operations team visibility into what ran, when, and what the outcome was. Build a simple admin page that shows recent payout jobs with their status, payout count, success rate, and any errors.

For the full automated payout system architecture, see building an automated payout system on Paystack.

Build Reliable Payout Operations

Payout scheduling is where engineering meets operations. Getting the timing, batching, and monitoring right means your vendors get paid on time, every time.

The McTaba bootcamp covers the operational side of payment systems alongside the code. You learn to build systems that work in production, not just in test mode.

Create a free McTaba account

Key Takeaways

  • ✓Schedule payouts at least one full settlement cycle after the revenue period ends. If settlement is T+1, run weekly payouts on Wednesday for the previous Monday-Sunday period.
  • ✓Batch transfers in groups of 100 using the bulk transfer endpoint. Add 2-3 second delays between batches to stay within rate limits.
  • ✓Run payouts during business hours (9 AM - 3 PM local time) for the fastest bank settlement. Avoid late night and early morning when banks run maintenance.
  • ✓For large payout runs (500+ transfers), split across multiple execution windows to reduce risk and allow partial completion tracking.
  • ✓Build a scheduler with cron or a job queue. Track each execution run with a batch ID so you can monitor progress and handle failures per batch.
  • ✓Separate scheduling (when) from execution (how). Let the scheduler determine timing, and let the execution engine handle the Paystack API calls.

Frequently Asked Questions

Can Paystack schedule transfers for a future date?
No. Paystack processes transfers immediately when you call the API. All scheduling logic must be built in your application using cron jobs, job queues, or task schedulers. This gives you more control over timing, approval, and error handling than a built-in scheduler would.
How should I handle a payout job that fails mid-execution?
The payouts that already went to Paystack continue processing. Payouts not yet sent remain in their current state. Your job should track which payouts were submitted and which were not. On the next run, only process the remaining ones. Deterministic references prevent duplicates if some payouts overlap between runs.
What is the best payout frequency for a marketplace?
Weekly payouts are the most common starting point for marketplaces. They balance vendor expectations (regular income) with operational overhead (one payout run per week). As you grow, consider offering faster payout options (daily or instant) as a premium feature for top vendors.

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 Transfers and Payouts: Complete Guide

Everything you need to send money out of your Paystack account: creating transfer recipients, initiating single and bulk transfers, handling OTP requirements, managing failures, and building automated payout systems for bank accounts, M-Pesa wallets, and mobile money across Africa.

Read more

Transfer OTP: Enabling, Disabling and Automating

Paystack requires OTP confirmation for transfers by default. This guide explains the OTP flow, how to disable it for automated payout systems, the security trade-offs of disabling OTP, and how to build your own application-level approval controls to replace OTP with something better suited to production automation.

Read more

Transfers to M-PESA Wallets, Paybills and Tills

Kenya runs on M-Pesa, and Paystack lets you send transfers to M-Pesa personal wallets, Paybill business accounts, and Till numbers. This guide covers creating recipients for each destination type, phone number formatting, account number requirements for Paybills, settlement timing, and the failure modes specific to M-Pesa transfers.

Read more

Building a Driver Payout System for a Ride Hailing App

Ride-hailing drivers need fast, reliable payouts. This guide covers building a driver payout system on Paystack: calculating trip-based earnings with commission deductions, daily settlement cycles, M-Pesa and bank payout options, handling cash-collected trips, real-time driver balance tracking, and instant withdrawal features.

Read more

Reconciling Paystack Against an M-Pesa Statement

Kenyan businesses receiving Paystack settlements via M-Pesa need to reconcile those settlements against their M-Pesa statement. The process is similar to bank reconciliation but with M-Pesa-specific quirks: Paybill references, till numbers, and Safaricom statement formats.

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.