Bill customers in their own currency
A working pattern for pricing in USD and charging in local money: which rate to fetch, when to lock it, what to store, and how to answer the invoice question that follows six months later.
A pricing job that converts a USD base price into every currency you sell in, locks the rate per subscription, and keeps a record that reproduces any past invoice exactly.
Fetch every rate you sell in, once
Ask for all your currencies in a single call rather than one call per customer. A daily job over nine currencies is one request, not nine.
curl "https://api.currency-rate-api.com/api/v1/rates/latest?base=USD&symbols=EUR,GBP,JPY,CHF,CAD,SEK,PLN,INR,BRL" \
-H "Authorization: Bearer YOUR_API_KEY"Rates update once daily via a scheduled ingestion job, so there is no reason to call this more than once a day per base currency — cache the response for the rest of the day.
Convert, then apply your margin
Convert the base price at the published rate, then apply whatever spread covers your payment costs. Keep the two operations separate so you can change the margin without re-deriving prices.
const mid = Number(rates.EUR);
const gross = basePriceUsd * mid;
const price = gross * (1 + marginPct / 100);
// 49.00 × 0.921000 × 1.015 = 45.82 EURRound at the very end. Our API always returns amounts to two decimal places — for a currency with no minor unit, like JPY, you still need to round to a whole unit yourself before charging.
Lock the rate on the subscription
Write the rate and its timestamp onto the subscription at signup, in your own database. The customer then sees a stable price, and a rate move mid-cycle does not surprise anyone.
await db.subscriptions.update(id, {
billingCurrency: 'EUR',
lockedRate: '0.921000',
lockedAt: '2026-08-06T00:00:00Z',
lockExpiresAt: addDays(now, 90),
});Ninety days is a common window. Shorter and customers notice churn in their bill; longer and you carry the currency risk.
Reproduce any past invoice
When a customer disputes a charge from March, fetch the historical rate for that exact date and show the arithmetic. It resolves in one reply instead of an escalation.
curl "https://api.currency-rate-api.com/api/v1/rates/2026-03-01?base=USD&symbols=EUR" \
-H "Authorization: Bearer YOUR_API_KEY"
# { "base": "USD", "date": "2026-03-01", "rates": { "EUR": "0.910700" } }
# 49.00 × 0.910700 × 1.015 = 45.31 EURWhat to store per charge
Choosing a lock policy
There is no universally right answer; pick the one your support team can explain in a sentence.
Convert at the moment each invoice is generated.
Fix the rate for a window, then refresh on renewal.
Set local prices by hand, review them quarterly.