A merchant selling digital products to customers in the UK collects £50 per sale through Paystack. On the day of collection, the Central Bank of Nigeria rate is ₦1,950/£. By the time she sits down to reconcile her books three weeks later, that rate has moved to ₦2,040/£.
Which number goes in her ledger?
The answer — and why it matters legally, practically, and for any accurate picture of your business — is the focus of this article. If your business collects payments in any currency other than Naira, this is one of the most important accounting questions you will face. Most tools get it wrong. Here is the correct approach and how KoboSync implements it.
Why the Exchange Rate Question Is Not Trivial
If you are collecting USD or GBP through Paystack or Flutterwave, what lands in your Nigerian bank account is Naira. The gateway converts at the prevailing rate on settlement day and credits your account in NGN. The original foreign currency amount is a data point — the Naira amount is the economic reality.
This creates three separate problems:
Problem 1: Which rate do you use for your records? The CBN official rate, the parallel market rate, and the rate Paystack or Flutterwave actually applies when settling your account are three different numbers. They can differ by 5–15% on any given day.
Problem 2: The rate changes between payment and reconciliation. If you collect payment today and reconcile next week, using today's rate gives you inaccurate historical records. The rate that was in effect on the day of the transaction is the legally correct one to record.
Problem 3: Refunds must use the original rate. If a customer pays $100 when the rate is ₦1,600/$ and you refund them six months later when the rate is ₦1,750/$, you have not refunded ₦175,000. You have refunded the Naira equivalent of the original $100 — which is ₦160,000. Using the current rate for refund accounting creates artificial FX losses or gains in your books.
All three problems have the same solution: lock the exchange rate at the moment of the transaction and never change it.
How KoboSync Handles Multi-Currency Transactions
When a payment arrives through any of our supported gateways, the webhook payload includes the transaction currency. For Paystack, this is the currency field on the charge object. Flutterwave includes it as well.
If the currency is NGN, no conversion is needed — the amounts are already in Naira and we record them directly. If the currency is anything else, we run a conversion pipeline immediately, at the moment the transaction is processed.
Step 1 — Identify the transaction currency
Our parser extracts the currency from the raw gateway payload:
currency: parseCurrency(d?.currency, "paystack"),The parseCurrency function validates against our list of supported currencies. If it encounters something unsupported — say, a CAD payment through a Paystack integration — it logs a warning rather than silently defaulting to NGN. A silent default would corrupt your records.
Step 2 — Get the exchange rate at transaction time
We do not use a live API call at the time of processing. Live rates change by the second, and a rate that was accurate when the webhook arrived may be different by the time our worker processes it. Instead we use the rate stored in our exchange_rates table for the date of the transaction.
const { exchangeRate, amountNgn, feeNgn, netNgn, vatAmountNgn } =
await exchangeRateService.computeNgnAmounts(
unified.currency,
gross,
fee,
net,
vatResult.vatAmount,
unified.transactionDate, // ← the actual payment date, not now()
bridge.ngnParallelRate ? Number(bridge.ngnParallelRate) : null,
);Two things worth noting here. First, we use unified.transactionDate — the timestamp of the actual payment as reported by the gateway — not the current time. This matters for backfill operations where you might be importing transactions from three months ago. Second, we support a ngnParallelRate override per bridge. Merchants who want to record at the parallel market rate rather than the official CBN rate can configure this in their bridge settings.
Step 3 — Store both the native and NGN amounts
Every transaction in our database stores two sets of financial figures:
amount — gross in the transaction's native currency (e.g. 100 for $100)
fee — gateway fee in native currency
net — net in native currency
amountNgn — gross converted to NGN at the locked rate
feeNgn — fee in NGN
netNgn — net in NGN
exchangeRate — the rate used for conversion, stored permanently
The exchangeRate field is immutable after creation. It represents the economic reality of that specific transaction on that specific day. If CBN rates change tomorrow, yesterday's transactions do not change.
What Goes in Your Google Sheet
When KoboSync writes the transaction row to your spreadsheet, foreign currency transactions get additional columns that NGN transactions do not:
| Date | Gateway | Reference | Customer | Gross | Fee | Net | Currency | Rate (NGN) | Gross (NGN) | Fee (NGN) | Net (NGN) | |------|---------|-----------|----------|-------|-----|-----|----------|------------|-------------|-----------|-----------| | 2026-04-28 | PAYSTACK | REF001 | buyer@email.com | 100 | 1.50 | 98.50 | USD | 1,610 | 161,000 | 2,415 | 158,585 |
The native currency columns let you cross-reference against your gateway dashboard (which reports in the original currency). The NGN columns are what you use for your actual accounting, tax filings, and FIRS submissions.
The Parallel Market Rate Question
This is where Nigerian business accounting gets genuinely complicated. The official CBN rate and the parallel market rate have historically differed significantly. Most Nigerian businesses that collect USD or GBP are effectively pricing in the parallel market rate — if you sell a $100 product, you are thinking in terms of what ₦160,000+ can buy you in Lagos, not the official rate.
FIRS does not currently prescribe which rate you must use for your accounts, though they do expect consistency. Using the official CBN rate understates your income in real terms. Using the parallel market rate is a more accurate reflection of the economic value you received but carries regulatory uncertainty.
KoboSync supports both approaches. By default we use the CBN official rate fetched from our exchange rate service. If you want to record at the parallel market rate, you set a custom NGN rate on your bridge settings — it applies to all transactions on that bridge from that point forward. You can update it whenever the market moves significantly.
Whatever rate you choose, use it consistently within a financial year. Switching mid-year to take advantage of rate movements creates accounting inconsistencies that can attract FIRS scrutiny. Document your rate policy and apply it uniformly.
Handling Refunds in a Multi-Currency Context
This is where most accounting tools fail completely. When you refund a customer who paid in USD, the refund amount in your records should be calculated at the original transaction's exchange rate, not the current rate.
Consider this scenario:
- Customer pays $100 in January at ₦1,600/$ → you record ₦160,000 in revenue
- Customer requests a refund in June when the rate is ₦1,850/$
- You refund $100 through your gateway
The economic reality is that you are reversing ₦160,000 of revenue — the amount you originally received. If you use the June rate, you would record ₦185,000 as the refund, which implies you had an FX gain of ₦25,000 on a transaction that net-net returned you nothing. That is not what happened.
KoboSync locks the exchange rate at the time of the original transaction and uses it for any subsequent refunds:
// In refund.service.ts — we read the original transaction's locked rate
const exchangeRateUsed = originalTx.exchangeRate
? Number(originalTx.exchangeRate)
: null;
// Convert using that locked rate, not a fresh one
amountRefundedNgn = input.amountRefunded * exchangeRateUsed;The refund row written to your sheet also shows both the native currency amount and the NGN equivalent at the original rate, with a note indicating which rate was used:
Reversal of REF001. NGN equivalent: ₦160,000 (rate: ₦1,610/USD on 2026-01-15)
What This Means for Your VAT Calculations
If you are on the Pro plan with VAT mode enabled, all VAT calculations run on the NGN amounts, not the native currency amounts. This is correct — Nigerian VAT is a Naira-denominated liability. FIRS does not care what currency your customer paid in; they care about the Naira value of the taxable supply.
Our VAT calculator receives the NGN-converted gross and applies the 7.5% rate to that figure:
const vatResult = calculateVat(gross, vatMode);
// gross here is already in the transaction's native currency
// VAT stored as vatAmount (native) and vatAmountNgn (converted)Your monthly tax summary aggregates vatAmountNgn across all transactions, regardless of what currency each individual transaction was denominated in. The FIRS statement shows a single NGN figure — your total VAT liability for the month — which is the correct presentation.
Supported Currencies
KoboSync currently supports: NGN, USD, GBP, EUR. These cover the vast majority of cross-border payments processed through Nigerian gateways.
If you receive payments in a currency not on this list — say, CAD or AUD — KoboSync will log a warning, default to NGN (treating the amount as already in Naira), and flag the transaction in your webhook inspector so you can review it manually. We do not silently corrupt your records with a bad conversion.
Support for additional currencies can be added — if you regularly receive payments in a currency not listed above, reach out to support@kobosync.com.
A Practical Checklist for Multi-Currency Nigerian Merchants
Before you start collecting foreign currency payments, here is what you should have in place:
- Decide on your exchange rate policy — CBN official or parallel market. Document the decision.
- Set your bridge's primary currency to the foreign currency if most of your revenue is in that currency. This affects how your dashboard analytics display figures.
- Set a custom NGN rate if needed — in bridge settings under Currency. Update it periodically (monthly is reasonable for most businesses).
- Verify your Google Sheet has the additional columns — KoboSync adds them automatically on the first foreign currency transaction.
- Do not manually delete the Rate (NGN) column from your sheet. KoboSync uses it for ledger consistency and will recreate it if it detects it is missing.
- For FIRS reporting, use the NGN figures in your tax summary, not the native currency amounts. Your accountant should understand this distinction.
KoboSync automatically handles exchange rate conversion, locked rates for refunds, and NGN-denominated VAT calculations — across Paystack, Flutterwave, and Monnify. Connect your first bridge free →
