Real-Time Exchange Rate API for Stock Portfolio Apps

Convert holdings in JPY, EUR, GBP, and other currencies into one base-currency portfolio view. Keep the stock-price timestamp separate from the FX timestamp.

Normalize multi-currency holdings into one portfolio value

Value each position in its trading currency, then convert that amount into the portfolio base currency with the matching FX rate. One latest-rates request can cover the currencies across a portfolio, so cache it at the portfolio calculation boundary rather than fetching the same rate once per holding.

The response carries source, a per-currency sources map, data_updated_at, and market_session. Actively traded currencies can update live, about every 60 seconds on trading days; the rest use ECB/FRED reference data. Persist the per-currency source used for each value, especially when a portfolio mixes live and daily-reference coverage.

Keep security-price and FX timestamps separate

A Tokyo-listed security can close hours before New York, while its JPY/USD conversion may be observed later. Store the security’s price timestamp beside the FX data_updated_at; do not label the combined value as if both inputs came from the same moment. Market holidays and closed sessions need the same care: market_session tells you when the FX market state is weekend or otherwise closed, not whether the stock exchange traded.

For base-currency P&L, keep local-currency price movement and FX movement as separate components. This makes a gain caused by the security easier to distinguish from a change in the reporting currency.

Backfill history without inventing a market close

Use historical rate data to reconstruct a valuation series or a dated P&L report. A one-date request may carry the prior published value across a weekend or holiday and marks that value with is_forward_filled. Range results omit non-publication days. Pair the observations with the dates and closing conventions of the security-price source you use.

These rates are indicative. They are not executable quotes, order-routing inputs, or trading prices, and they should not be used to place or settle an order. Use the broker, exchange, or custodian record for execution and settlement facts.

Server-side portfolio valuation

Keep the API key on your server. This example records the rate and its freshness fields alongside the value your application calculated.

TypeScript · server-side portfolio valuation
type LatestRates = {
  rates: Record<string, number>;
  sources: Record<string, 'live' | 'ecb_daily' | 'fred_daily'>;
  data_updated_at: string;
  market_session: 'open' | 'weekend' | 'interbank_closed';
};

const response = await fetch(
  'https://api.exchangerate.dev/v1/latest/USD?symbols=EUR,JPY,GBP',
  { headers: { Authorization: `Bearer ${process.env.EXR_API_KEY}` }, next: { revalidate: 60 } },
);
if (!response.ok) throw new Error('Could not load FX rates');

const fx = (await response.json()) as LatestRates;
const holding = { symbol: '7203', currency: 'JPY', marketValue: 2_840_000, priceAsOf: '2026-08-19T06:00:00Z' } as const;
const rate = fx.rates[holding.currency];
const source = fx.sources[holding.currency];
if (!Number.isFinite(rate) || !source) throw new Error('Missing JPY FX data');

// Implement this adapter with your server-side database client.
await savePortfolioValuation({
  ...holding, base_currency: 'USD', base_value: holding.marketValue / rate,
  fx_rate: rate, fx_source: source,
  fx_updated_at: fx.data_updated_at, fx_market_session: fx.market_session,
});

Ready to test the API?

Start with the quickstart, check the response fields, and see pricing when you need account quota.

Free is for evaluation and internal, non-commercial use. Basic and Pro include commercial use.

Create a free evaluation key →