Bonaventure OgetoBy Bonaventure Ogeto|

Split Payment Reconciliation and Subaccount Reporting

Query GET /transaction?subaccount=SUB_xxx to list all transactions for a specific subaccount. Compare the amount field (minus fees) against your internal orders table for that vendor. Build vendor earnings statements by joining your orders table with subaccount settlement data. Flag transactions where the expected vendor share differs from the actual settled amount by more than NGN 1.

Per-Vendor Earnings from Your Database

-- Vendor earnings statement for a specific month
SELECT
  v.id as vendor_id,
  v.business_name,
  v.subaccount_code,
  COUNT(o.id) as order_count,
  SUM(o.total_amount) as gross_sales,
  SUM(o.platform_commission) as platform_commission,
  SUM(o.total_amount - o.platform_commission) as net_earnings,
  SUM(o.paystack_fee_absorbed) as fees_absorbed,
  SUM(o.total_amount - o.platform_commission - o.paystack_fee_absorbed) as settled_amount
FROM vendors v
JOIN orders o ON o.vendor_id = v.id
WHERE o.status = 'paid'
  AND o.paid_at BETWEEN '2026-07-01' AND '2026-07-31'
GROUP BY v.id, v.business_name, v.subaccount_code
ORDER BY net_earnings DESC;

Weekly Reconciliation Script

// Pull Paystack transactions per subaccount and compare
async function reconcileSubaccount(subaccountCode) {
  var response = await fetch(
    'https://api.paystack.co/transaction?subaccount=' + subaccountCode + '&status=success&perPage=100',
    { headers: { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY } }
  );
  var { data } = await response.json();

  var discrepancies = [];

  for (var tx of data) {
    var localOrder = await db.orders.findOne({
      where: { reference: tx.reference, subaccount_code: subaccountCode }
    });

    if (!localOrder) {
      discrepancies.push({ type: 'missing_local', reference: tx.reference });
      continue;
    }

    var expectedVendorShare = localOrder.total_amount - localOrder.platform_commission;
    var actualVendorShare = tx.subaccount?.amount / 100;

    if (Math.abs(expectedVendorShare - actualVendorShare) > 1) {
      discrepancies.push({
        type: 'amount_mismatch',
        reference: tx.reference,
        expected: expectedVendorShare,
        actual: actualVendorShare,
      });
    }
  }

  return discrepancies;
}

Learn More

Key Takeaways

  • Use GET /transaction?subaccount=SUB_xxx to pull all transactions for a specific vendor subaccount.
  • Your local database is the source of truth for expected vendor share — compare against Paystack API data.
  • Build per-vendor monthly earnings statements from your orders table for vendor portal dashboards.
  • Run a weekly reconciliation script that flags any transaction where actual settlement differs from expected.
  • Use the Paystack settlement endpoint (GET /settlement) to see what has actually been paid out to each subaccount.
  • Store the subaccount_code on every order record to enable fast per-vendor reporting without calling the Paystack API.

Frequently Asked Questions

How do I show vendors their earnings in a vendor portal?
Query your local orders table by vendor_id for the date range. Display: total sales, platform commission deducted, Paystack fee (if vendor bears), and net earnings. Do not call the Paystack API on every vendor portal page load — use your local database for fast queries.
What is the difference between transaction amount and settled amount for a subaccount?
The transaction amount is what the customer paid. The subaccount settled amount is what Paystack transferred to the vendor after deducting the platform commission and any applicable Paystack fee. Always reconcile against settled amounts, not transaction amounts.
Can I get a bulk settlement report from Paystack?
Yes. Use GET /settlement to list all settlements. Pass subaccount=SUB_xxx to filter by vendor. The settlement endpoint shows the exact NGN amount transferred to each subaccount bank account, which is your definitive payout record.
How do refunds affect vendor earnings in reconciliation?
A refund reverses the split. If you refund NGN 5,000 on a transaction where the vendor received NGN 4,000, Paystack deducts NGN 4,000 from the vendor subaccount settlement. Reflect this in your vendor earnings reports by subtracting refunded amounts from gross sales.

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