Back to blog
PrimentraPrimentra
·July 13, 2026·8 min read

Currency master data: the stale exchange rate that cost €40,000

Home/Blog/Currency master data: the stale exchange rate that cost €40,000
EUR/USD · DAILY RATE FEEDFEED FAILED · SUN 03:00frozen 1.0857actual 1.1012$2.4M paid on the frozen rate · €40,900 short · nothing errored

The payment was for 2.4 million dollars, going to a components supplier in Ohio, and it left the treasury system converted from euros at a rate of 1.0857. That rate was correct three weeks earlier. A scheduled job pulled the daily rates from the central bank every morning at three, and one Sunday it failed without a sound, so the table kept serving the last figures it had received. The euro had moved almost a cent and a half in the meantime. Nobody typed a wrong number and nobody approved a bad rate. The payment simply converted at a price that had stopped being true, and the company was €40,900 lighter than the invoice said it should be.

Currency is the master data domain everyone assumes is solved, because ISO already handed you the codes. USD, EUR, JPY, three letters each, a list you can paste in an afternoon. That list is the easy half, and finishing it feels like finishing the job. The half that actually moves money is the rates, and the rates are almost never owned by anyone.

It is two things wearing one name

A currency record looks like one thing and behaves like two. The first is the code: a controlled value that says EUR or JPY, the same everywhere, drawn straight from the ISO 4217 standard, carrying a name, a symbol, and the number of decimal places the currency actually uses. That part is reference data, and it governs the way any reference list does: one authorized set, one owner, change control in front of it.

The second is the exchange rate, and it is a different animal entirely. A rate is not a value, it is a value with a date attached. EUR/USD is 1.0857 as of a specific morning and something else by the next. It also has a type and a source. Store a rate without its effective date and you have not stored a rate, you have stored a rumor. This is the same shape as a conversion factor in unit of measure, except the factor between a case and an each never changes, and the factor between two currencies changes every day the market is open.

Which rate did you actually mean

Here is the part that surprises people the first time it bites them. On any given day, the same currency pair has several correct rates. There is the spot rate for settling a payment now. There is the monthly average, used to translate a period of revenue. There is the period-end closing rate, used to revalue a balance sheet. And in many companies there is a budget rate, fixed once a year, so that currency swings do not muddy whether a division hit its numbers.

All four are right. They are right for different purposes. The failure happens when two systems value the same transaction with two different rate types and both insist they are correct, because they are. If the rate type is an assumption living in one person's head rather than an attribute living on the data, you cannot even have the argument cleanly, because nobody can say which rate was meant. The rate type is master data. Treating it as a convention is how a reconciliation turns into a week.

Where currency breaks

None of these is a typo. In every one, the codes were valid and the people did their jobs. The damage lives in the rates and the rules around them.

The feed that froze

A scheduled job pulls the daily rates from the central bank at three in the morning. One Sunday it fails, silently, and no one owns the job. The rate table keeps serving the last values it received, every system converts against them, and nothing errors because a slightly old rate is a perfectly valid number. Three weeks later every converted figure is wrong by however far the market moved, and the first symptom is a payment that came up short.

The missing rate that became 1

A new currency turns up in a transaction before anyone loaded its rate. The consolidation routine needs a number, finds none, and falls back to 1. Now 500,000 yen and 500,000 dollars are added as though they were the same amount, and a regional rollup overstates one market by two orders of magnitude. It is the same failure as a conversion factor left at 1, wearing a different currency symbol.

The wrong number of decimals

Most currencies have two minor units, so most systems assume two. The Japanese yen has none and the Bahraini dinar has three. A payment file built on the two-decimal assumption turns 1,000 yen into 10.00 and a 1.234 dinar amount into 1.23, and the rounding lands in a suspense account that a controller reconciles by hand every month.

The code that is not ISO

Someone types RMB instead of CNY, or keeps using a code that was retired years ago. The internal systems tolerate it because they always have. The bank file, the tax return, and the partner API do not, because they validate against ISO 4217, so the payment or the filing bounces at the worst possible moment with the least helpful error message.

The rate applied on the wrong date

An invoice dated last month is booked today, and the posting logic reaches for the current rate instead of the rate that was true on the invoice date. One line is trivially off. Ten thousand lines at month-end produce a revaluation swing that finance cannot explain, and someone spends two days proving the business did not lose money, the date logic did.

They have one thing in common: the arithmetic never complains. A stale rate, a missing rate that became 1, a rate applied on the wrong day, each one runs cleanly and returns a number, and a number that looks reasonable is the hardest kind of error to catch. It is exactly how a report ends up confidently wrong while every job in the pipeline reports success.

Rules that keep the rates honest

Give every rate the four things that make it a rate: an effective date, a type, a source, and an owner. A rate with no date cannot be applied to a back-dated transaction correctly, and a rate with no owner is a rate that will freeze one Sunday and stay frozen until a payment comes up short.

Monitor the feed as data, not as a job. A job that succeeds tells you the script ran. A freshness check on the data tells you the rates are actually current: if no rate for an active currency is newer than a day, something is wrong, and it should raise an alert before it raises an invoice. And never let a missing rate quietly become 1. A conversion with no rate should stop and ask, not guess.

Keep the code list honest against ISO 4217, decimals included, and validate that amounts respect each currency's actual precision, so nobody books three decimals of yen or rounds a dinar to two. When a rate has to be entered or overridden by hand, and sometimes it does, make that an approved change with the reason recorded, the same as any other edit to financial master data. An override with no trail is the line item an auditor circles first.

If you are coming off MDS

Microsoft MDS could hold the currency code list without much trouble, as an entity with a code, a name, and a few attributes. What it had no concept of was a rate: a value that is only meaningful with a date and a type attached, changing every day, arriving from a feed. So in every MDS estate I have seen, the rates lived somewhere else. A spreadsheet a treasury analyst updated by hand. A homegrown table with no audit and no approval, written to by a nightly job nobody documented. The master data platform governed the three-letter codes and washed its hands of the numbers that actually did the converting.

If you are migrating off MDS, that split is the thing worth fixing on the way across. Rates belong under the same governance as the rest of your master data: effective-dated, typed, owned, audited, with approval in front of a manual override. The migration is also a good moment to find out how many currencies in your systems are running on a rate nobody has refreshed since the last person who cared about it left. The number is rarely zero, and you would rather learn it now than from a payment that comes up short.

Common questions

What is currency master data?

Two things under one name. A static list of currency codes from the ISO 4217 standard, each with its name, symbol, and number of decimal places. And a live time series of exchange rates, where every rate has an effective date, a type, and a source. The code list is reference data shared everywhere. The rates change daily, and they are the part almost nobody governs.

Why does a stale or missing exchange rate cause wrong numbers?

Because a slightly wrong rate is still a valid number, so nothing errors. A frozen feed keeps serving old rates and every conversion drifts by however far the market has moved. A missing rate often defaults to 1, which adds unlike currencies as though they were equal. Either way the arithmetic runs cleanly and returns a total that is quietly false.

What is a rate type and why does it matter which one you use?

The same pair has several correct rates on the same day: the spot rate, a monthly average, the period-end closing rate, and sometimes a fixed budget rate. Each is right for a different purpose. If two systems value the same transaction with different rate types they disagree on the amount and both are right, which is why the rate type has to be part of the data, not an assumption.

Where should exchange rates be governed?

In the same place as the rest of your master data, with an owner, an effective date, a rate type, a source, and an audit trail. Feeds should be monitored as data, not just as a job, so a freshness check alerts when no rate has arrived recently. Manual overrides should be a governed change with a reason recorded, not a quiet edit to a spreadsheet.

Make the rate behind the number something you can trust

Primentra governs currency codes and effective-dated rates as first-class master data, runs changeset-based approvals on manual overrides, and keeps the full audit trail of who changed which rate and when. It runs on your own SQL Server, deploys in a day, and costs €7,500 per year flat. The 60-day trial is long enough to bring a real rate table under control.

Start free trial →Try the demo →

More from the blog

The chart of accounts is master data, and finance is running it from a spreadsheet9 min readReference data management: the part of your MDM strategy that breaks first8 min readProduct discontinuation: the item that kept ordering itself8 min read

Ready to migrate from Microsoft MDS?

Join the waitlist and be the first to try Primentra. All features included.

Download Free TrialTry DemoCompare MDM tools
Currency master data: the stale exchange rate that cost €40,000 | Primentra