CurrencyRateDocs
Docs › Guides › Billing › Bill customers in their own currency
Guide12 min read

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.

WHAT YOU'LL BUILD

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.

GET /api/v1/rates/latestGET /api/v1/rates/{date}GET /api/v1/convert
01

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
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.

02

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.

JavaScript
const mid   = Number(rates.EUR);
const gross = basePriceUsd * mid;
const price = gross * (1 + marginPct / 100);

// 49.00 × 0.921000 × 1.015 = 45.82 EUR

Round 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.

03

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.

JavaScript
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.

04

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
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 EUR
Watch out. Never re-convert a stored local amount back to USD for reporting. Round-tripping introduces drift that grows with every cycle. Store both amounts and the rate at the moment of charge.

What to store per charge

COLUMN
TYPE
WHY
base_amount
decimal
The price in your pricing currency, before any conversion.
base_currency
char(3)
Usually USD. Store it anyway; pricing currencies change.
charged_amount
decimal
What the customer actually paid, in their money.
charged_currency
char(3)
The currency on the payment, not the customer's country.
rate
decimal
The rate used, at full precision, from the API response.
rate_taken_at
timestamp
The date field from the API response, not your server clock.
margin_pct
decimal
Lets you separate FX from your own spread when reporting.

Choosing a lock policy

There is no universally right answer; pick the one your support team can explain in a sentence.

Live at charge

Convert at the moment each invoice is generated.

+ No currency risk carried
Bill changes every month
Locked at signup

Fix the rate for a window, then refresh on renewal.

+ Predictable for the customer
You absorb the move
Published price list

Set local prices by hand, review them quarterly.

+ Clean, round numbers
Manual, and drifts