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 Transaction Export and Reporting via API
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Paystack Transaction Export and Reporting via API

Paystack provides a Transaction List endpoint to query transactions with filters (date range, status, customer, amount) and a Transaction Export endpoint to generate downloadable CSV files. Together they let you build automated reporting pipelines that pull transaction data daily, reconcile against your internal records, and feed financial systems.

In this article

  1. 1. Listing Transactions with Filters
  2. 2. Paginating Through Large Result Sets
  3. 3. The Transaction Export Endpoint
  4. 4. Building an Automated Daily Report
  5. 5. Reconciling Transactions Against Your Orders
  6. 6. Using Metadata for Richer Reports
  7. 7. Stay Up to Date

Listing Transactions with Filters

The transaction list endpoint is your primary tool for querying payment data. It returns an array of transaction objects with full details.

// List successful transactions from the past 7 days
const sevenDaysAgo = new Date(Date.now() - 7 * 86400000).toISOString();
const now = new Date().toISOString();

const response = await fetch(
  'https://api.paystack.co/transaction?from=' + sevenDaysAgo +
  '&to=' + now +
  '&status=success' +
  '&perPage=100' +
  '&page=1',
  {
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    },
  }
);

const data = await response.json();
console.log('Total transactions:', data.meta.total);
console.log('Page:', data.meta.page, 'of', data.meta.pageCount);

for (const tx of data.data) {
  console.log(
    tx.reference + ' | ' +
    tx.customer.email + ' | ' +
    (tx.amount / 100) + ' ' + tx.currency + ' | ' +
    tx.status
  );
}

Available filter parameters:

  • from / to: Date range in ISO format. Always set these to avoid pulling your entire transaction history.
  • status: "success", "failed", or "abandoned". Filter by payment outcome.
  • customer: Customer ID to see all transactions for a specific customer.
  • amount: Filter by exact amount (in kobo/pesewas). Useful for finding a specific payment.
  • perPage: Number of results per page (default 50, max 200).
  • page: Page number for pagination.

For reporting, always paginate through all results. The meta object in the response tells you the total count and page count. Loop through pages until you have all records.

Paginating Through Large Result Sets

If you process hundreds or thousands of transactions daily, a single API call will not return everything. You need to paginate.

async function getAllTransactions(from, to, status) {
  let allTransactions = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const response = await fetch(
      'https://api.paystack.co/transaction?from=' + from +
      '&to=' + to +
      '&status=' + status +
      '&perPage=200' +
      '&page=' + page,
      {
        headers: {
          Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
        },
      }
    );

    const data = await response.json();
    allTransactions = allTransactions.concat(data.data);

    if (page >= data.meta.pageCount) {
      hasMore = false;
    } else {
      page++;
    }
  }

  return allTransactions;
}

// Usage
const transactions = await getAllTransactions('2026-07-21', '2026-07-22', 'success');
console.log('Total fetched:', transactions.length);

Set perPage to 200 (the maximum) to minimize the number of API calls. Be mindful of rate limits. If you are pulling data for a long date range with many transactions, add a small delay between page requests to avoid hitting rate limits.

Store the fetched data in your own database or data warehouse. Do not query Paystack in real-time for every dashboard view or report request. Pull the data periodically and serve reports from your own store.

Get weekly developer tips

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

No spam. Unsubscribe anytime.

The Transaction Export Endpoint

For bulk data pulls (monthly reports, tax filings, audits), the export endpoint generates a CSV file with all matching transactions.

// Request a transaction export
const response = await fetch('https://api.paystack.co/transaction/export', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
  },
});

const data = await response.json();
// data.data.path = URL to download the CSV file
console.log('Download URL:', data.data.path);

You can filter the export with the same parameters as the list endpoint: from, to, status, customer, etc. Append them as query parameters.

// Export only successful transactions for July 2026
const exportUrl = 'https://api.paystack.co/transaction/export?from=2026-07-01&to=2026-07-31&status=success';
const response = await fetch(exportUrl, {
  headers: {
    Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
  },
});

const data = await response.json();
// Download the CSV from data.data.path

The export is generated asynchronously. For small datasets, the URL may be available immediately. For large datasets (thousands of transactions), generation takes a few minutes. The download URL is temporary. Download the file promptly and store it in your own storage.

The CSV contains columns for reference, amount, currency, status, customer email, payment channel, fees, created date, and other transaction fields. The exact columns may vary as Paystack updates the export format.

Building an Automated Daily Report

Here is a complete daily reporting pipeline that pulls the previous day's transactions, summarizes them, and stores the report.

async function dailyTransactionReport() {
  const yesterday = new Date(Date.now() - 86400000);
  const from = yesterday.toISOString().split('T')[0];
  const to = new Date().toISOString().split('T')[0];

  // Pull all successful transactions
  const successful = await getAllTransactions(from, to, 'success');

  // Pull all failed transactions
  const failed = await getAllTransactions(from, to, 'failed');

  // Calculate summary
  const totalRevenue = successful.reduce(function(sum, tx) { return sum + tx.amount; }, 0);
  const totalFees = successful.reduce(function(sum, tx) { return sum + (tx.fees || 0); }, 0);
  const totalNet = totalRevenue - totalFees;

  // Group by payment channel
  const byChannel = {};
  for (const tx of successful) {
    const channel = tx.channel || 'unknown';
    if (!byChannel[channel]) {
      byChannel[channel] = { count: 0, amount: 0 };
    }
    byChannel[channel].count++;
    byChannel[channel].amount += tx.amount;
  }

  const report = {
    date: from,
    successful_count: successful.length,
    failed_count: failed.length,
    total_revenue_kobo: totalRevenue,
    total_fees_kobo: totalFees,
    total_net_kobo: totalNet,
    by_channel: byChannel,
  };

  // Store in database
  await db.query(
    'INSERT INTO daily_reports (report_date, data) VALUES ($1, $2)',
    [from, JSON.stringify(report)]
  );

  console.log('Daily report for ' + from + ':');
  console.log('  Successful: ' + successful.length + ' transactions');
  console.log('  Failed: ' + failed.length + ' transactions');
  console.log('  Revenue: ' + (totalRevenue / 100).toLocaleString() + ' NGN');
  console.log('  Fees: ' + (totalFees / 100).toLocaleString() + ' NGN');
  console.log('  Net: ' + (totalNet / 100).toLocaleString() + ' NGN');

  return report;
}

Schedule this function to run every morning via a cron job or a scheduled cloud function. It gives your finance team a daily summary without them needing to log into the Paystack dashboard.

Reconciling Transactions Against Your Orders

The most important reporting task is making sure every Paystack transaction matches an order in your system. Here is a reconciliation approach:

async function reconcileTransactions(from, to) {
  const paystackTxns = await getAllTransactions(from, to, 'success');
  const mismatches = [];

  for (const tx of paystackTxns) {
    // Look up the order in our database
    const order = await db.query(
      'SELECT id, amount, status FROM orders WHERE paystack_reference = $1',
      [tx.reference]
    );

    if (order.rows.length === 0) {
      mismatches.push({
        type: 'no_order',
        reference: tx.reference,
        amount: tx.amount,
        message: 'Paystack transaction exists but no matching order found',
      });
      continue;
    }

    const dbOrder = order.rows[0];

    // Check amount match
    if (dbOrder.amount !== tx.amount) {
      mismatches.push({
        type: 'amount_mismatch',
        reference: tx.reference,
        paystack_amount: tx.amount,
        order_amount: dbOrder.amount,
        message: 'Amount mismatch between Paystack and order record',
      });
    }

    // Check status match
    if (dbOrder.status !== 'paid' && dbOrder.status !== 'settled') {
      mismatches.push({
        type: 'status_mismatch',
        reference: tx.reference,
        order_status: dbOrder.status,
        message: 'Paystack shows success but order is not marked as paid',
      });
    }
  }

  if (mismatches.length > 0) {
    console.log('Found ' + mismatches.length + ' mismatches:');
    for (const m of mismatches) {
      console.log('  ' + m.type + ': ' + m.reference + ' - ' + m.message);
    }
    // Send alert to finance team
  } else {
    console.log('All ' + paystackTxns.length + ' transactions reconciled successfully');
  }

  return mismatches;
}

Run this alongside your daily report. It catches orders that were paid on Paystack but not recorded in your system (missed webhooks), amount mismatches (partial payments or bugs), and status inconsistencies.

Using Metadata for Richer Reports

If you pass metadata when initializing transactions, that metadata appears in the transaction list and export. This opens up powerful reporting dimensions.

// When creating the transaction, include metadata
const initResponse = await fetch('https://api.paystack.co/transaction/initialize', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'customer@example.com',
    amount: 500000,
    metadata: {
      product_type: 'subscription',
      plan: 'pro',
      campaign: 'july_promo',
      referral_source: 'twitter',
    },
  }),
});

// Later, in your report, filter or group by metadata
const transactions = await getAllTransactions('2026-07-01', '2026-07-31', 'success');

const byCampaign = {};
for (const tx of transactions) {
  const campaign = (tx.metadata && tx.metadata.campaign) || 'organic';
  if (!byCampaign[campaign]) {
    byCampaign[campaign] = { count: 0, revenue: 0 };
  }
  byCampaign[campaign].count++;
  byCampaign[campaign].revenue += tx.amount;
}

console.log('Revenue by campaign:', JSON.stringify(byCampaign, null, 2));

Plan your metadata schema before launch. Consistent metadata keys across all transactions make reporting straightforward. Inconsistent or missing metadata makes it impossible to slice data later. See metadata guide for schema design patterns.

Stay Up to Date

Paystack updates their transaction and export APIs as they add new fields and features. We keep these guides current.

Join the McTaba newsletter for Paystack engineering updates.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓The Transaction List endpoint (/transaction) returns paginated transaction records with support for filtering by date, status, customer, and amount. Use it for real-time queries and dashboard displays.
  • ✓The Transaction Export endpoint (/transaction/export) generates a CSV file containing all transactions matching your filters. Paystack emails you a download link or returns a URL. Use it for bulk data pulls and accounting system imports.
  • ✓Always filter by date range when listing transactions. Without a date filter, the API returns your most recent transactions across all time, which may not be what you need for reporting.
  • ✓Transaction amounts in the API are in the smallest currency unit (kobo, pesewas, cents). Divide by 100 before displaying or importing into accounting software.
  • ✓Build automated daily exports as a cron job. Pull the previous day's transactions, store them in your reporting database, and flag any that do not match your internal order records.
  • ✓The export endpoint is asynchronous. You request the export, Paystack generates the file, and you get a download URL. For large datasets, generation may take a few minutes.

Frequently Asked Questions

How far back can I query Paystack transaction data?
The Paystack Transaction List API does not have a documented time limit on historical queries. You can query transactions from the day you created your Paystack account. However, pulling very long date ranges without pagination will be slow. Always paginate and set reasonable date ranges for your queries.
What format does the Paystack transaction export use?
The export generates a CSV (comma-separated values) file. It includes columns for reference, amount, currency, status, customer email, payment channel, fees, and timestamps. You can import this CSV into Excel, Google Sheets, or any accounting software that supports CSV import.
Are transaction fees included in the transaction list response?
Yes. Each transaction object in the list response includes a fees field that shows the processing fee Paystack charged for that specific transaction. The fee is in the smallest currency unit (kobo, pesewas, cents). The net amount you receive is the transaction amount minus the fee.
Can I export failed and abandoned transactions?
Yes. Use the status filter parameter with "failed" or "abandoned" to export those transaction types. This is useful for analyzing payment failure rates, understanding why customers abandon checkout, and identifying issues with specific card types or banks.
Is there a rate limit on the transaction list endpoint?
Paystack applies rate limits to all API endpoints. The exact limits are not publicly documented and may vary by account. If you are building automated reporting, add a small delay (1 to 2 seconds) between paginated requests to stay well within limits. If you hit rate limits, the API returns a 429 status code. Back off and retry after a few seconds.

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 Behind Nginx and a Reverse Proxy

A troubleshooting and configuration guide for running Paystack webhook endpoints behind Nginx or another reverse proxy. Covers the most common issues: body buffering that corrupts signature verification, missing X-Paystack-Signature headers, proxy timeouts, and X-Forwarded-For headers. Includes tested Nginx configuration blocks you can copy into your setup.

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.