Guides

Currencies and Exchange Rates

Bill in any ISO currency or one of your own, keep every balance in its own currency, and report in one currency at the rate of each payment's day.

PimaBill keeps money in the currency it was charged in. A customer billed in UGX owes UGX, pays UGX, and appears in your UGX totals. Nothing is converted except reports, which add every currency up in one reporting currency so you can see the whole business at once.

Any ISO currency

Customers, prices, add-ons, wallets and invoices take any ISO 4217 code, such as UGX, KES, NGN, XOF, USD or EUR, with the right number of decimals for each: none for UGX, two for KES, three for KWD. A code that is neither ISO nor one of your own is refused, so a typo like UGS never becomes a price.

Your own currencies

Bill in something that isn't an ISO currency, such as loyalty points, credits, a stablecoin or vouchers, by defining it first in Settings → Currencies, or with the API:

curl -X POST https://api.pimabill.com/api/currencies/custom \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "code": "PTS", "name": "Loyalty points", "decimals": 0, "perUsd": 100 }'
  • code: 2 to 10 letters or digits, not an ISO code.
  • decimals: 0 to 8. Amounts round to this.
  • perUsd: optional. How many units make one US dollar, used to include the currency in reports. Without it, the currency is left out of converted totals, and reports list it under unconverted.

After that, use PTS anywhere a currency goes. A currency in use can't be removed, and its decimals can't change.

Payment providers only move real money, so collections and payouts stay in ISO currencies.

Reporting currency

Analytics and the dashboard overview add every currency up in your reporting currency. It starts as your country's currency (UGX for an organisation in Uganda, KES in Kenya) and can be changed in Settings → Currencies or with PUT /api/currencies/reporting.

Every analytics response says what it is in:

{ "mrr": "8400000.00", "currency": "UGX", "ratesAsOf": "2026-10-25", "unconverted": [] }

Exchange rates

Rates are fetched once a day and kept by date. Each payment is converted at the rate of the day it was paid, so last month's revenue doesn't change when the shilling moves. Recurring revenue uses today's rate. Payments older than the rate history use the earliest rate available.

To see money exactly as it is, use the Money by currency card on the overview, or GET /api/analytics/by-currency. It shows what was collected this month and last, what is outstanding, and recurring revenue in each currency, with nothing converted.

Self-hosting? Rates come from open.er-api.com by default. Set EXCHANGE_RATES_URL to any source that answers { "rates": { "UGX": 3650.5, ... } } against USD (for example Open Exchange Rates with your app ID), or to off to turn fetching off.

Copyright © 2026