# Storing Exchange Rates for Multi-Currency Systems

**Quick Answer: When building an e-commerce system, never use today's exchange rate to calculate the value of past transactions. Currency values fluctuate daily. To keep financial analytics accurate, you must store the exact exchange rate on the transaction record at checkout, or fetch the precise historical rate at runtime.**

Building a system to sell things online seems straightforward until international money enters the picture. Imagine your team is building a storefront that sells t-shirts. Your main operations are in the UK, so your base currency is GBP. Everything works perfectly until an overseas customer buys a shirt using USD. You convert the dollars to pounds, ship the shirt, and everyone goes home happy.

Fast forward a year. Your team runs analytics to calculate the total annual revenue. This is exactly where I see developers get tripped up.

## Why shouldn't I use current exchange rates for past transactions?

Using current exchange rates for past transactions skews your reporting. Currencies fluctuate from day to day, meaning calculating a purchase from a year ago with today's rate will give you inaccurate historical revenue numbers.

When that customer bought the t-shirt last year, the GBP to USD rate was specific to that exact day. If you didn't record that rate, and you try to calculate the transaction value using today's rate, your analytics will simply be wrong. I have seen developers hardcode an exchange rate into a configuration file and use it forever because it feels "roughly right." But roughly right usually means being quite off—sometimes by 10% or 20% in some instances. That adds up quickly when you are trying to total up all your transactions over the course of a year.

## How should I store multi-currency transactions in a database?

You should save the exchange rate directly on the transaction row at the exact moment the checkout completes. This saves the exact state of the conversion alongside the purchase data, giving you an accurate record for future analytics.

Instead of relying on math later, make the math a permanent part of the database record. When the checkout succeeds, your backend needs to capture the original currency amount, the exchange rate applied, and the final converted amount in your base currency. 

Here is exactly what you need to capture to avoid historical inaccuracies:

* **Original Amount:** The exact numeric value the user paid (e.g., 20.00).
* **Original Currency:** The ISO currency code used by the buyer (e.g., USD).
* **Exchange Rate:** The exact multiplier used at the time of purchase (e.g., 0.78).
* **Base Amount:** The final calculated value in your system's default currency (e.g., 15.60).
* **Base Currency:** Your system's default currency (e.g., GBP).
* **Timestamp:** The exact time the transaction completed.

Let's look at a brief SQL schema to visualize this:

```sql
CREATE TABLE transactions (
    id UUID PRIMARY KEY,
    original_amount DECIMAL(10, 2),
    original_currency VARCHAR(3),
    exchange_rate DECIMAL(10, 6),
    base_amount DECIMAL(10, 2),
    created_at TIMESTAMP
);
```

## Should I store exchange rates or fetch them at runtime?

Storing the exchange rate directly in your database is highly recommended because it simplifies data retrieval and speeds up reporting. Fetching historical rates dynamically at runtime from an external API is possible, but it introduces heavy network latency to your analytics pipeline.

If you really want to calculate things after the fact, you can hit a financial API at runtime to ask for the historical GBP to USD exchange rate for a specific past date. But doing this for thousands of rows during an analytics run is a significant performance bottleneck. 

Storing the rate directly on the transaction acts as a cache and a reliable historical source of truth. It guarantees that if the external API goes down, or you migrate to a new payment provider, your internal revenue calculations remain perfectly stable.

## FAQ

### How do you handle refunds in a different currency?
Refunds should generally use the exact exchange rate of the original transaction to avoid losing money on currency fluctuations. Alternatively, some payment gateways refund the exact original currency amount and force the merchant to absorb the difference. Either way, you must record the refund rate just like you record the purchase rate.

### What data type should I use for currency exchange rates?
Always use a decimal or numeric data type (like DECIMAL or NUMERIC in SQL) with high precision, such as 4 to 6 decimal places. Never use floating-point types for financial data because they introduce fractional rounding errors.

### How often should e-commerce platforms update live exchange rates?
For live checkouts, most platforms update their exchange rates at least daily, though high-volume trading platforms might update them every few minutes. You should use a reliable third-party API and cache the rate locally for your specified time window to keep checkout fast.
