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. Paystack Balance and Settlement APIs Explained
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Paystack Balance and Settlement APIs Explained

The Paystack Balance API returns your available and ledger balance per currency. The Settlement API lists settlement batches with gross amount, fees, net amount, settlement date, and status. Together they let you build automated reconciliation that matches Paystack payouts against your bank statement entries.

In this article

  1. 1. The Balance API: What You Have Right Now
  2. 2. Listing Settlements: The Settlement API
  3. 3. Drilling Into Settlement Transactions
  4. 4. Building a Reconciliation System
  5. 5. Using Balance Data for Transfer Decisions
  6. 6. Multi-Currency Balances
  7. 7. Common Mistakes with Balance and Settlement Data
  8. 8. Stay Up to Date

The Balance API: What You Have Right Now

The balance endpoint tells you how much money is sitting in your Paystack account at this moment. It is a read-only snapshot.

const response = await fetch('https://api.paystack.co/balance', {
  headers: {
    Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
  },
});

const data = await response.json();
// data.data is an array of balance objects
// Example response:
// [
//   { "currency": "NGN", "balance": 15000000 },
//   { "currency": "GHS", "balance": 500000 }
// ]

The balance value is in the smallest currency unit: kobo for NGN, pesewas for GHS, cents for ZAR and KES. To get the human-readable amount, divide by 100. So 15000000 kobo is NGN 150,000.

If you accept payments in multiple currencies, you get one balance entry per currency. A Nigerian business that also accepts GHS payments will see two entries.

What the balance includes:

  • Successful charges that have not yet been settled
  • Pending transfers that have not yet been processed
  • Refunds that have been initiated but not yet deducted from the next settlement

What the balance does not include:

  • Charges that are still in progress (pending or abandoned)
  • Money that has already been settled to your bank account

The balance is useful for two things: knowing if you have enough funds to initiate a transfer, and monitoring your account health at a glance.

Listing Settlements: The Settlement API

The settlement endpoint lists every settlement batch Paystack has sent (or attempted to send) to your bank account.

// List settlements with optional date filters
const response = await fetch(
  'https://api.paystack.co/settlement?from=2026-07-01&to=2026-07-22',
  {
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    },
  }
);

const data = await response.json();
// data.data is an array of settlement objects
// Each object:
// {
//   "id": 12345,
//   "total_amount": 5000000,    // Gross charges included (kobo)
//   "total_fees": 75000,        // Fees deducted (kobo)
//   "net_amount": 4925000,      // What was sent to your bank (kobo)
//   "currency": "NGN",
//   "status": "success",        // or "pending" or "failed"
//   "settlement_date": "2026-07-22T00:00:00.000Z"
// }

Key fields in each settlement object:

  • total_amount: The sum of all charges included in this settlement, before fee deduction. This is the gross number.
  • total_fees: The total processing fees Paystack deducted from this batch.
  • net_amount: total_amount minus total_fees. This is the amount that was actually sent to your bank. This is the number you should match against your bank statement.
  • status: "success" means the money was sent. "pending" means the settlement is scheduled but not yet processed. "failed" means the bank rejected it and Paystack will retry.
  • settlement_date: The date the settlement was processed or is scheduled for.

Pagination: The settlement endpoint returns results in pages. Use the perPage and page query parameters to navigate through large result sets.

Get weekly developer tips

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

No spam. Unsubscribe anytime.

Drilling Into Settlement Transactions

When you find a settlement whose net amount does not match your bank credit, you need to see the individual transactions that were included. The settlement transactions endpoint gives you this breakdown.

// Get transactions included in settlement #12345
const response = await fetch(
  'https://api.paystack.co/settlement/12345/transactions',
  {
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    },
  }
);

const data = await response.json();
// data.data is an array of transactions
// Each transaction contains:
// - reference: your transaction reference
// - amount: charge amount in kobo
// - fees: fee deducted for this transaction
// - customer: { email, ... }
// - created_at: when the charge happened

This endpoint lets you trace every kobo. If your bank statement shows a credit of NGN 49,250 but your records say you should have received NGN 50,000, you can pull the settlement transactions, sum the fees, and find the exact source of the difference.

Common reasons for discrepancies:

  • Refunds deducted from settlement: If you refunded a transaction between the charge and the settlement, the refund amount is subtracted from the settlement batch.
  • Chargebacks deducted: If a customer filed a chargeback and the dispute was resolved against you, the chargeback amount is deducted from a future settlement.
  • Fee calculation differences: Fee caps, percentage tiers, and channel-specific rates mean that total fees are not simply "flat rate times number of transactions."

Building a Reconciliation System

Here is a practical reconciliation workflow that runs as a daily background job.

async function reconcileSettlements() {
  // 1. Fetch yesterday's settlements from Paystack
  const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0];
  const today = new Date().toISOString().split('T')[0];

  const response = await fetch(
    'https://api.paystack.co/settlement?from=' + yesterday + '&to=' + today,
    {
      headers: {
        Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      },
    }
  );
  const settlements = await response.json();

  for (const settlement of settlements.data) {
    // 2. Check if we already reconciled this settlement
    const existing = await db.query(
      'SELECT id FROM reconciled_settlements WHERE paystack_settlement_id = $1',
      [settlement.id]
    );
    if (existing.rows.length > 0) continue;

    // 3. Fetch the transactions in this settlement
    const txResponse = await fetch(
      'https://api.paystack.co/settlement/' + settlement.id + '/transactions',
      {
        headers: {
          Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
        },
      }
    );
    const transactions = await txResponse.json();

    // 4. Cross-check against our orders
    let matchedCount = 0;
    let unmatchedRefs = [];

    for (const tx of transactions.data) {
      const order = await db.query(
        'SELECT id FROM orders WHERE paystack_reference = $1 AND status = $2',
        [tx.reference, 'paid']
      );

      if (order.rows.length > 0) {
        await db.query(
          'UPDATE orders SET status = $1, settled_at = $2 WHERE paystack_reference = $3',
          ['settled', settlement.settlement_date, tx.reference]
        );
        matchedCount++;
      } else {
        unmatchedRefs.push(tx.reference);
      }
    }

    // 5. Record the reconciliation result
    await db.query(
      'INSERT INTO reconciled_settlements (paystack_settlement_id, net_amount, matched, unmatched, reconciled_at) VALUES ($1, $2, $3, $4, $5)',
      [settlement.id, settlement.net_amount, matchedCount, unmatchedRefs.length, new Date()]
    );

    // 6. Alert on unmatched transactions
    if (unmatchedRefs.length > 0) {
      console.log('Unmatched transactions in settlement ' + settlement.id + ': ' + unmatchedRefs.join(', '));
      // Send alert to finance team
    }
  }
}

Run this job daily after the settlement window closes. In Nigeria with T+1 settlement, run it in the morning to catch the previous day's settlement.

Using Balance Data for Transfer Decisions

If you use Paystack Transfers to pay vendors, contractors, or customers, your available balance is the funding source. Before initiating a transfer, check that you have enough balance.

async function canTransfer(amountInKobo, currency) {
  const response = await fetch('https://api.paystack.co/balance', {
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    },
  });

  const data = await response.json();
  const balanceEntry = data.data.find(function(b) { return b.currency === currency; });

  if (!balanceEntry) {
    return { canTransfer: false, reason: 'No balance in ' + currency };
  }

  if (balanceEntry.balance < amountInKobo) {
    return {
      canTransfer: false,
      reason: 'Insufficient balance. Available: ' + (balanceEntry.balance / 100) + ' ' + currency + ', Required: ' + (amountInKobo / 100) + ' ' + currency,
    };
  }

  return { canTransfer: true, available: balanceEntry.balance };
}

This check prevents transfer failures due to insufficient balance. Paystack rejects transfers that exceed your available balance, but checking beforehand gives you a chance to show a meaningful error message or queue the transfer for later.

Keep in mind that the balance can change between your check and the actual transfer request. If multiple transfer requests happen concurrently, you could pass the balance check but still fail the transfer. Handle the insufficient balance error from the Transfer API as a fallback.

Multi-Currency Balances

If your Paystack account accepts payments in multiple currencies, the Balance API returns a separate entry for each currency. Settlements happen per currency too. A GHS settlement goes to your Ghana bank account, and an NGN settlement goes to your Nigerian bank account.

When building financial dashboards or reports, display each currency balance separately. Do not convert and sum them. Exchange rates fluctuate, and your accounting system needs to track each currency independently.

async function displayBalances() {
  const response = await fetch('https://api.paystack.co/balance', {
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    },
  });

  const data = await response.json();

  for (const entry of data.data) {
    const amount = entry.balance / 100;
    console.log(entry.currency + ': ' + amount.toLocaleString());
  }
  // Output:
  // NGN: 150,000
  // GHS: 5,000
}

For settlement reconciliation across currencies, run separate reconciliation jobs for each currency. Each currency has its own settlement schedule, fee structure, and bank account destination.

For the broader picture of how settlement fits into the accept payments workflow, see the complete accept payments guide. For settlement timing specifics, see settlement timelines and what engineers should assume.

Common Mistakes with Balance and Settlement Data

These mistakes show up repeatedly in production integrations:

  • Comparing gross amounts to bank credits. The bank credit is the net amount (after fees). If you compare the settlement total_amount against your bank statement, every single settlement will show a discrepancy. Always use net_amount.
  • Ignoring failed settlements. A settlement with status "failed" means Paystack tried to pay you and the bank rejected it. The money is still in your Paystack balance. It will be retried on the next cycle. If you only track "success" settlements, you will think money is missing when it is actually queued for retry.
  • Caching balance data. The balance changes with every charge and every settlement. Do not cache it for more than a few seconds. If you need to display the balance on a dashboard, fetch it fresh each time the page loads.
  • Not paginating settlement queries. If your account processes many transactions, a single settlement API call might not return all results. Always check for pagination and iterate through all pages.
  • Hardcoding fee calculations. Fees vary by channel, volume tier, and country. Never calculate expected fees in your application. Read the actual fee from the settlement data.

Stay Up to Date

Paystack updates their settlement and balance APIs as they add features and markets. We keep these guides current when things change.

Join the McTaba newsletter for new Paystack engineering content.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓The Balance API endpoint (/balance) returns an array of balance objects, one per currency. Each object contains the available balance (funds ready for settlement or transfer) in the smallest currency unit (kobo, pesewas, cents).
  • ✓The Settlement API endpoint (/settlement) lists settlement batches. Each batch contains the total gross amount, total fees deducted, net amount sent to your bank, settlement date, and status (success, pending, or failed).
  • ✓Available balance is money from successful charges that has not yet been settled. It is the pool from which Paystack pays you on the next settlement cycle and from which you can initiate transfers.
  • ✓The settlement net amount is always less than the gross amount because Paystack deducts processing fees. Your reconciliation logic must compare net amounts, not gross amounts, against bank credits.
  • ✓You can filter settlements by date range, status, and subaccount. This makes it possible to reconcile daily, weekly, or monthly depending on your accounting needs.
  • ✓Use the settlement transactions endpoint to see which individual transactions were included in a specific settlement batch. This is essential for tracing discrepancies.

Frequently Asked Questions

What is the difference between available balance and ledger balance on Paystack?
The available balance is money from successful charges that has not yet been settled or transferred. It is the amount you can use for transfers right now. The ledger balance is the cumulative total of all charges, settlements, refunds, and transfers. The Balance API typically returns the available balance. Check your Paystack dashboard for the ledger balance breakdown.
How often should I check my Paystack balance via the API?
It depends on your use case. If you are displaying the balance on an admin dashboard, fetch it each time the page loads. If you are checking before initiating transfers, fetch it right before each transfer. Do not poll the balance endpoint continuously. There is no webhook for balance changes, so a periodic check (or on-demand fetch) is the right approach.
Can I get settlement data for a specific subaccount?
Yes. If you use Paystack subaccounts for marketplace splits, you can filter settlement data by subaccount. Pass the subaccount parameter when querying the settlement endpoint to see settlements for a specific subaccount.
Why does my settlement show zero fees for some transactions?
Some transaction types or promotional periods may have zero or reduced fees. Also, if a fee cap applies and you have already hit the cap for that transaction, the individual fee may be lower than expected. Check with Paystack support if you see consistently unexpected fee amounts.
How do refunds affect my settlement?
If you issue a refund after the transaction has been settled, the refund amount is deducted from a future settlement. If you issue a refund before settlement, the refunded transaction is excluded from the settlement batch entirely. Either way, refunds reduce the net amount you receive.

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

Accepting Payments with Paystack: Complete Guide

Everything you need to accept your first payment with Paystack: choosing between Initialize Transaction and the Charge API, handling amounts in kobo, attaching metadata, setting callback URLs, and designing transaction references that keep your system clean.

Read more

Paystack Metadata: Passing Custom Data Through a Transaction

Paystack metadata lets you attach arbitrary JSON data to a transaction that flows through the entire lifecycle: from initialization to verification to webhooks. This guide shows you what to put in metadata, how to structure it for different use cases, and the limits you need to stay within.

Read more

Paystack Product API for Simple Storefronts

The Paystack Product API lets you create products with names, prices, and descriptions, then generate payment links for each one. For simple storefronts selling a handful of products, this is faster than building a full e-commerce backend. This guide covers creating products, linking them to payment pages, and knowing when to outgrow this approach.

Read more

Reconciling Dedicated Virtual Account Deposits

Dedicated Virtual Accounts (DVAs) let each customer have a permanent bank account number linked to your Paystack integration. When a customer transfers money to their DVA, Paystack notifies you. But matching those deposits to the right customer, handling partial payments, and reconciling against your records requires careful engineering. This guide walks through the reconciliation workflow.

Read more

Paystack Webhooks and CSRF Protection in Django

A focused guide on fixing the 403 Forbidden error when Paystack webhooks hit your Django application. Covers why Django CSRF protection blocks webhook POST requests, how to use @csrf_exempt safely, the Django REST Framework approach, and a complete Django webhook view with signature verification.

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.