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. Currency Handling in Paystack: NGN, GHS, ZAR, KES and USD
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 20, 2026

Currency Handling in Paystack: NGN, GHS, ZAR, KES and USD

To set the currency for a Paystack transaction, pass the currency field (e.g., "NGN", "GHS", "ZAR", "KES", "USD") when initializing. If omitted, Paystack defaults to your account primary currency. Each currency is tied to the country where your Paystack business is registered, and available payment channels vary by currency.

In this article

  1. 1. Supported Currencies Overview
  2. 2. Setting the Currency in a Transaction
  3. 3. Payment Channels by Currency
  4. 4. Currency-Aware Transaction Initialization
  5. 5. Verifying Currency in Responses
  6. 6. Settlement Behavior by Currency
  7. 7. Common Currency Mistakes
  8. 8. Stay Up to Date

Supported Currencies Overview

Paystack processes payments in five currencies, each tied to a specific market:

  • NGN (Nigerian Naira): The original and most feature-complete Paystack market. Supports card, bank transfer, USSD, QR, and dedicated virtual accounts.
  • GHS (Ghanaian Cedi): Supports card and mobile money. Mobile money is the dominant payment method in Ghana.
  • ZAR (South African Rand): Supports card payments. The South African market has high card adoption.
  • KES (Kenyan Shilling): Supports card and M-Pesa integration. M-Pesa is the dominant payment channel in Kenya.
  • USD (US Dollar): Available on some Paystack accounts, primarily for international collections. Payment channels are typically card-only.

The currencies available on your account depend on where your business is registered and what Paystack has enabled. A Nigerian-registered business gets NGN by default. To accept GHS, you would typically need a Ghana-registered entity or request multi-currency activation from Paystack. Check your dashboard under Settings to see which currencies are active on your account.

Setting the Currency in a Transaction

Pass the currency field when calling /transaction/initialize:

// Initialize a transaction in GHS
var response = 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: 50000,       // 500 GHS in pesewas
    currency: 'GHS',     // Explicitly set the currency
    callback_url: 'https://yoursite.com/payment/callback',
  }),
});

If you omit the currency field, Paystack uses your account's primary currency. For a Nigerian account, this means NGN. If your customer selected GHS and you forgot to pass it, the customer gets charged in Naira. The amount 50000 becomes 500 NGN instead of 500 GHS. This mismatch is silent from the API's perspective. The transaction initializes and processes without error. You only discover the problem when the customer complains or when reconciliation reveals the discrepancy.

Rule: always pass currency explicitly, even if your application only supports one currency today. It makes your code self-documenting and protects you if you add currencies later.

Get weekly developer tips

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

No spam. Unsubscribe anytime.

Payment Channels by Currency

Not all payment channels are available in all currencies. Here is the general landscape:

ChannelNGNGHSZARKESUSD
Card (Visa/Mastercard)YesYesYesYesYes
Bank TransferYesNoNoNoNo
USSDYesNoNoNoNo
Mobile MoneyNoYesNoNoNo
QRYesNoNoNoNo
Dedicated Virtual AccountsYesNoNoNoNo
Apple PayYesYesYesYesYes

This table reflects the general availability. Paystack may enable or restrict channels based on your account type and business category. Always check your dashboard or contact Paystack support for your specific account's channel availability.

When you restrict channels with the channels parameter, only pass channels that are available for the transaction's currency. If you pass channels: ['mobile_money'] for an NGN transaction, the checkout will have no valid payment option and the customer will be stuck. For more on channel restriction, see restricting payment channels at checkout.

Currency-Aware Transaction Initialization

If your application serves customers in multiple countries, you need to select the right currency based on the customer's location or preference. Here is a pattern that handles this cleanly:

// Currency configuration by country
var currencyConfig = {
  NG: { code: 'NGN', channels: ['card', 'bank_transfer', 'ussd'] },
  GH: { code: 'GHS', channels: ['card', 'mobile_money'] },
  ZA: { code: 'ZAR', channels: ['card'] },
  KE: { code: 'KES', channels: ['card'] },
};

app.post('/api/pay', async function(req, res) {
  var country = req.body.country; // 'NG', 'GH', 'ZA', 'KE'
  var config = currencyConfig[country];

  if (!config) {
    return res.status(400).json({ error: 'Unsupported country' });
  }

  var response = 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: req.body.email,
      amount: Math.round(req.body.displayAmount * 100),
      currency: config.code,
      channels: config.channels,
      callback_url: 'https://yoursite.com/payment/callback',
    }),
  });

  var data = await response.json();
  res.json(data.data);
});

This pattern ensures the currency and available channels always match. A Ghanaian customer sees card and mobile money options. A Nigerian customer sees card, bank transfer, and USSD. No one sees a channel that does not work for their currency.

Verifying Currency in Responses

When you verify a transaction, check the currency field alongside the amount and status:

app.get('/payment/callback', async function(req, res) {
  var reference = req.query.reference;
  var order = await db.orders.findByReference(reference);

  var verifyResponse = await fetch(
    'https://api.paystack.co/transaction/verify/' + reference,
    {
      headers: {
        Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      },
    }
  );

  var data = await verifyResponse.json();
  var tx = data.data;

  // Verify ALL three: status, amount, and currency
  var amountMatch = tx.amount === order.amount_minor;
  var currencyMatch = tx.currency === order.currency;
  var statusMatch = tx.status === 'success';

  if (statusMatch && amountMatch && currencyMatch) {
    await fulfillOrder(order.id);
    res.redirect('/order/success');
  } else {
    console.log('Verification failed:');
    console.log('  Status: ' + tx.status + ' (expected success)');
    console.log('  Amount: ' + tx.amount + ' (expected ' + order.amount_minor + ')');
    console.log('  Currency: ' + tx.currency + ' (expected ' + order.currency + ')');
    res.redirect('/order/failed');
  }
});

Why check the currency? Because 500000 kobo (5,000 NGN) and 500000 cents (5,000 USD) are very different amounts. If an attacker manages to initialize a transaction in NGN for a price listed in USD, the amount integer matches but the real value is off by orders of magnitude. The currency check catches this.

The same applies to webhook handlers. The charge.success webhook payload includes both amount and currency. Verify both.

Settlement Behavior by Currency

Settlement timelines and procedures differ by currency and market. While the exact details depend on your account configuration and Paystack's current policies (which change over time), here are general patterns engineers should know:

  • NGN settlements: Typically settle to your Nigerian bank account. The standard cycle is next business day (T+1) for most businesses.
  • GHS settlements: Settle to your Ghanaian bank account. Settlement cycles may differ from NGN.
  • ZAR settlements: Settle to your South African bank account.
  • KES settlements: Settle to your Kenyan bank account.
  • USD settlements: Settlement details depend on your account setup. Some accounts receive USD settlements; others have USD converted to local currency before settlement.

From an engineering perspective, the key thing to understand is that settlement is not the same as payment success. A payment can succeed (charge.success) and the money can take hours or days to reach your bank account. Your system should grant value to the customer when the payment succeeds, not when the settlement arrives. For more on settlement timelines, see settlement timelines and what engineers should assume.

Common Currency Mistakes

Mistake 1: Hardcoding NGN when your app supports multiple currencies

Early in development, you might hardcode currency: 'NGN' and forget to make it dynamic. When you launch in Ghana, Ghanaian customers get charged in Naira. Always pull the currency from the order or customer context.

Mistake 2: Displaying one currency and charging another

Your frontend shows "GH¢ 500" but your server sends currency: 'NGN', amount: 50000. The customer pays 500 NGN instead of 500 GHS. The amount integer looks the same but the currencies are different. Always derive the currency from the same source as the display price.

Mistake 3: Assuming all channels work for all currencies

If you pass channels: ['bank_transfer'] for a GHS transaction, the checkout shows no payment options. Bank transfer is only available for NGN. Check channel availability for each currency before restricting channels.

Mistake 4: Not handling currency in refunds

Refunds are processed in the same currency as the original transaction. You cannot charge in NGN and refund in GHS. The refund amount is in the same smallest unit as the charge.

Stay Up to Date

Paystack continues to expand into new markets and may add new currencies or payment channels. We update these guides as things change.

Sign up for the McTaba newsletter to stay informed about Paystack currency and market updates.

Key Takeaways

  • ✓Paystack supports five currencies: NGN, GHS, ZAR, KES, and USD. The currencies available to you depend on your business registration country.
  • ✓Always pass the currency parameter explicitly when initializing a transaction. If omitted, Paystack defaults to your account primary currency, which can cause wrong charges for multi-currency setups.
  • ✓Payment channels vary by currency. Card payments work across all currencies. Bank transfers, USSD, and mobile money have country-specific availability.
  • ✓Amounts are always in the smallest currency unit (kobo, pesewas, cents) regardless of which currency you use. The multiplier is 100 for all Paystack currencies.
  • ✓Currency and amount verification during transaction verification is essential. Check both the amount and the currency code match what you expected.
  • ✓You cannot convert between currencies through Paystack. If you accept multiple currencies, each transaction is in a single currency.

Frequently Asked Questions

Can I accept payments in a currency my Paystack account is not registered for?
Generally no. Your available currencies are tied to your business registration and what Paystack has enabled on your account. You may need to register a business entity in the target country or request multi-currency activation from Paystack support.
Does Paystack handle currency conversion?
Paystack does not convert between currencies during a transaction. If a customer pays in GHS, you receive GHS. If you need to convert that to another currency, you handle that through your bank or a separate forex process.
Can I charge a Nigerian customer in USD?
If your account supports USD transactions, you can initialize a transaction in USD regardless of where the customer is located. However, the customer's bank may apply cross-border fees or conversion charges on their end. For Nigerian customers, charging in NGN usually provides a better experience.
What currency does the webhook payload use?
The webhook payload includes the currency field matching whatever currency the transaction was initialized in. The amount is in the smallest unit of that currency. Both are included in the data object of the webhook event.

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

Using Paystack Custom Fields to Collect Extra Checkout Information

Paystack custom fields let you attach structured, human-readable data to a transaction that shows up on the checkout page, in your dashboard, and in webhook payloads. This guide covers display_name vs variable_name, common field patterns, and how to extract custom field data when the webhook arrives.

Read more

Paystack Customer Objects: Create, Fetch, Update, Whitelist

Paystack creates a customer object every time a new email hits your checkout. You can also create customers explicitly, update their details, fetch their transaction history, and whitelist or blacklist them for risk control. This guide covers every operation with working Node.js code.

Read more

Building a Wallet Top-Up Flow on Paystack

A step-by-step guide to building wallet top-up flows with Paystack. Initialize payment, handle webhooks, credit wallets safely, enforce minimum amounts, and prevent double-crediting in production.

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.