Most bugs in currency code are not network errors – they are direction errors. A rate read the wrong way around, an inverse taken from a rounded value, or a cross rate computed with the division flipped will produce numbers that look plausible and are wrong. This page explains how base currency, quote currency and cross rates fit together, so the arithmetic in your code matches what the data means.
A cross rate is an exchange rate between two currencies that is calculated through a third currency, typically the US dollar. If you know how many euros and how many yen one US dollar buys, dividing one by the other gives the EUR/JPY cross rate without needing a direct EUR/JPY quote.
Base currency and quote currency
A currency pair is written BASE/QUOTE. The rate tells you how many units of the quote currency one unit of the base currency costs.
EUR/USD = 1.0850
└─ base: EUR (1 unit)
└─ quote: USD (1.0850 units)
=> 1 EUR = 1.0850 USD
A foreign exchange rates API uses the same idea with explicit parameters. In fxapi, base_currency is the “1 unit” side and each entry in data is a quote currency:
{
"meta": { "last_updated_at": "2026-10-08T09:31:00Z" },
"data": {
"USD": { "code": "USD", "value": 1.085 },
"JPY": { "code": "JPY", "value": 163.2 }
}
}
With base_currency=EUR, this (illustrative) response reads “1 EUR = 1.085 USD” and “1 EUR = 163.2 JPY”. The default base is USD.
Market quote conventions
In the interbank market, each major pair has a conventional direction. Dealers quote EUR/USD, not USD/EUR. The usual priority for which currency becomes the base is EUR, then GBP, AUD, NZD, USD, and then the other currencies.
| Pair as quoted | Reads as | Notes |
|---|---|---|
| EUR/USD | 1 EUR in USD | Most traded pair |
| GBP/USD | 1 GBP in USD | Nicknamed “cable” |
| AUD/USD, NZD/USD | 1 AUD or NZD in USD | Commonwealth currencies quoted as base |
| USD/JPY | 1 USD in JPY | USD is the base |
| USD/CHF, USD/CAD | 1 USD in CHF or CAD | USD is the base |
| EUR/GBP, EUR/JPY | 1 EUR in GBP or JPY | Euro crosses keep EUR as base |
Conventions matter when you compare your numbers with a newspaper, a terminal or a bank statement. An API does not have to follow them: you choose the base. Just make sure your UI labels say which way the rate reads.
Inverse rates
To flip a pair, divide 1 by the rate:
EUR/USD = 1.0850
USD/EUR = 1 ÷ 1.0850 = 0.92165898…
Two rules prevent subtle errors:
- Invert the full-precision value. If you round 1.0850 to 1.09 first, the inverse becomes 0.9174 instead of 0.9217 – a 0.5% error.
- Mid-market inverses are exact; retail inverses are not. For a mid-market rate,
1 ÷ rategives the mid in the other direction. For bid/ask quotes, the inverse of the bid is the ask of the flipped pair, so retail rates cannot be inverted one-for-one.
Computing cross rates from a USD base
Suppose you hold one response with base_currency=USD. Each value r[X] means “units of X per 1 USD”. The rate from currency A to currency B is:
rate(A → B) = r[B] ÷ r[A]
Worked example (illustrative values):
| Code | Units per 1 USD |
|---|---|
| EUR | 0.9200 |
| GBP | 0.7700 |
| JPY | 150.00 |
EUR → JPY = 150.00 ÷ 0.9200 = 163.0435 (1 EUR = 163.04 JPY)
GBP → EUR = 0.9200 ÷ 0.7700 = 1.1948 (1 GBP = 1.1948 EUR)
JPY → GBP = 0.7700 ÷ 150.00 = 0.0051333 (1 JPY = 0.00513 GBP)
A quick sanity check: the target currency’s value goes on top. If EUR→JPY comes out below 1, the division is upside down.
Triangulation
Calculating through a third currency is called triangulation. In the market, triangular arbitrage keeps direct crosses close to their triangulated value: if EUR/JPY drifted away from EUR/USD × USD/JPY, traders would buy the cheap side and sell the expensive one until the gap closed. That is why a cross computed from two mid-market rates is a sound reference – but it will not match a directly quoted cross to the last digit, because the direct quote has its own spread and timestamp.
Always triangulate from one snapshot. Mixing a EUR rate from 09:00 with a JPY rate from 15:00 produces a cross that never existed.
When to compute crosses and when to ask for a new base
| Situation | Recommended approach |
|---|---|
| A few pairs, rarely | Call the API with the base you need, e.g. base_currency=EUR |
| Many pairs, frequent display | Cache one USD-based response and derive crosses locally |
| Metals or crypto as base | Use the API base directly (base_currency=XAU or BTC) to avoid tiny divisors |
| Accounting amounts | Request the exact base and date your policy requires, and store the response |
fxapi accepts every one of its 190+ codes as base_currency on every plan, so the first option never costs extra. The second option saves requests: one cached call to /v1/latest contains enough information to derive tens of thousands of currency pairs. See caching exchange rates for cache lifetimes per plan.
Precision: keep digits until the end
Cross rates multiply rounding errors, so:
- Store rates with full precision as returned (fxapi returns values like
0.8890791312). - Use decimal types for money:
decimal.Decimalin Python,BigDecimalin Java,decimalin C#, or integer minor units in JavaScript. - Round once, at the end, to the target currency’s minor unit – 2 decimals for EUR, 0 for JPY, 3 for KWD. The
/v1/currenciesendpoint returnsdecimal_digitsper currency, and ISO 4217 currency codes explains minor units.
The currency rounding and precision guide covers rounding modes and display formatting in depth.
Example: derive any cross from one fxapi call
// One request, any pair: fetch USD-based rates once, then derive crosses locally.
const res = await fetch("https://api.fxapi.com/v1/latest?base_currency=USD", {
headers: { apikey: process.env.FXAPI_KEY },
});
const { data, meta } = await res.json();
const perUsd = (code) => (code === "USD" ? 1 : data[code].value);
export function crossRate(from, to) {
return perUsd(to) / perUsd(from); // target on top
}
console.log(`1 EUR = ${crossRate("EUR", "JPY").toFixed(4)} JPY (as of ${meta.last_updated_at})`);
console.log(`1 GBP = ${crossRate("GBP", "CHF").toFixed(6)} CHF`);
If you would rather not compute anything, the currency converter API (/v1/convert, Basic and up) returns converted amounts directly for any base. For a broader introduction, read what is an exchange rate API, or see the US dollar page for USD-specific notes.
Key takeaways
- The base currency is the “1 unit” side; the value is how many quote-currency units it costs.
- Invert with
1 ÷ rate, always on full-precision values. - Cross rate from a USD base:
rate(A → B) = r[B] ÷ r[A], from a single snapshot. - Round once, at the end, to the target currency’s minor unit.
Frequently asked questions
What is a cross rate?
What is the base currency in an exchange rate?
How do I invert an exchange rate?
Do I need to calculate cross rates myself with fxapi?
base_currency to any of the 190+ supported codes and fxapi returns all rates relative to it. Computing crosses locally is still useful when you want to derive many pairs from one cached response.