Multi-Currency and Exchange Rates in Dynamics 365 That Survive an Audit
A technical guide for the admin facing a period-end audit: what Dataverse stores for currency amounts, when rates are captured and recalculated, a dated rate table and stamping design, a period report that reconciles to finance, and the pitfalls auditors find.
Dataverse stores each currency amount twice: in the record's transaction currency and in the organization's base currency, converted with the exchange rate held on that record. The rate is captured when the record is created and refreshed when its currency or amounts are updated; changing a currency's rate later does not restate existing records. For an audit, do not rely on the single live rate. Keep a dated exchange rate table, write down which date governs each record type, stamp the rate, rate date and source on each record, lock them after period close, and report per period in a way that reconciles to the finance system of record. Watch base currency, rounding and migrated records.
What does Dynamics 365 actually store for a multi-currency record?
Every table with a currency column gets two system columns: transactioncurrencyid, the lookup to the currency the record is in, and exchangerate, the rate that was applied. Each currency column then has a companion base column, so estimatedvalue on an opportunity sits next to estimatedvalue_base, and totalamount on a quote or order sits next to totalamount_base.
The currencies themselves live in the Currency table (transactioncurrency). Each active currency holds one exchange rate, expressed as units of that currency per one unit of the base currency, and the base amount is the transaction amount divided by the record's rate. There is one base currency per environment, set when the environment's database is created.
The important word for an auditor is "one". The Currency table holds the current rate only. It is not a rate history, and Dynamics 365 does not fetch rates from any market source: someone or something has to update them.
| Column | What it holds | What an auditor should know |
|---|---|---|
| transactioncurrencyid | The currency the record is in | Defaults from the user or organization when not set; changing it later refreshes the rate |
| exchangerate | The rate applied to this record | Copied from the Currency table at the time of the last refresh, not at a business date you choose |
| amount column, for example totalamount | The value in the transaction currency | The figure the customer saw on the quote or order |
| amount_base column, for example totalamount_base | The value converted to base currency | Calculated by the platform from the amount and the record rate; read-only |
| Currency table exchange rate | The current rate for that currency | Overwritten on each update, so no history unless you audit or copy it |
When does Dynamics 365 capture or recalculate the exchange rate on a record?
The rate is taken from the Currency table when the record is created. It is refreshed when the record's currency changes, and when a currency amount on the record is updated, at which point the platform reads the current rate from the Currency table and recalculates the base columns. Updating the rate on the Currency table does not touch records that already exist: an opportunity created in January keeps its January rate until someone edits a money value on it.
That has two consequences. History is not restated when rates move, which is what most auditors want. But a harmless edit, such as correcting a discount in March on a January order, silently moves the record to March's rate and changes its base value, which is what auditors do not want.
The precise triggers, and how quote, order and invoice lines behave when a parent total is recalculated, are platform behaviour that Microsoft can change. Before you design controls around them, verify the current behaviour in a test environment: create a record, change the currency rate, edit a non-money column, then edit a money column, and read exchangerate and the base columns after each step. Check current Microsoft documentation for currency columns alongside that test.
Why is the single live exchange rate not enough evidence for an audit?
Because an auditor asks which rate was used for a transaction, where it came from, and whether it was the rate your policy says should apply. The live model answers none of those reliably. The record rate reflects the moment of the last refresh, not the invoice date, order date or close date your finance policy names. The Currency table keeps no history of its own. And base values can move after period close whenever someone edits an amount.
Auditing on the Currency table and on the transaction tables helps, because it records who changed the rate and which amount columns changed, and our Dynamics 365 audit trail guide covers turning it on and keeping it. But reconstructing every rate from audit history at year end is slow and fragile. It is far easier to store the evidence on the record at the moment it matters.
What does an audit-ready exchange rate design look like?
Four pieces, all standard Dataverse configuration plus a small amount of logic. None of them replaces the native columns; they sit alongside them so sellers keep working as before.
- A dated exchange rate table: a custom table with currency, effective date, rate against base, rate source (for example the reference rate your finance team uses), who loaded it and when. Add an alternate key on currency and effective date so loads are repeatable, and make the table read-only for everyone except the loading identity.
- A written governing date rule: for each record type, which date selects the rate. For example, orders use the order date, invoices the invoice date and opportunities the close date. Agree it with finance and match the finance system of record, not what is convenient in the CRM.
- Stamped columns on each financial record: rate used, rate effective date, rate source reference and the amount converted at that rate. They are written by a plug-in or flow when the governing date is set or the amount changes, and never typed by users.
- A period lock: once a period is closed, a plug-in refuses changes to amounts, currency and stamped columns on records dated in that period, unless a controlled adjustment process is followed and audited.
How do you choose which date governs the exchange rate?
Take the rule from finance, write it down, and apply it the same way everywhere. The CRM should not have its own opinion about exchange rates. If finance converts invoices at the invoice date rate from a named daily reference rate, the CRM uses the same date, the same source and the same fallback when a date has no rate, for example the most recent earlier business day.
Record the rule where both teams can see it: in the solution documentation and in a description on the stamped columns. Decide what happens when the governing date changes after stamping, such as a close date moving from one month to the next. Usually the stamp is recalculated until the period closes and frozen afterwards. The worst outcome is two rules, one in the CRM and one in finance, that agree most months and disagree in the month an auditor samples.
How do you stamp the rate used on each record?
With server-side logic that runs whenever a record is created or its governing date, currency or amount changes, so the stamp is correct whether the record came from a form, an import or an integration. A synchronous plug-in is the most dependable option because it runs in the same transaction as the save. A Power Automate flow works for lower volumes, with the caveat that it runs after the save and needs retry handling. Unit testing that logic is covered in our plug-in unit testing guide.
| Step | What the logic does |
|---|---|
| Find the rate | Look up the dated rate table for the record currency and governing date, using the agreed fallback when no rate exists for that exact date |
| Fail loudly | If no rate can be found, block the save or flag the record for review rather than stamping zero or the live rate |
| Write the stamp | Store rate used, effective date, source reference and the converted amount in the stamped columns |
| Respect period close | Skip or refuse the change if the governing date falls in a closed period |
| Optionally align native columns | Keep the Currency table rate in step with the latest dated rate so native base columns stay close, while reporting uses the stamps |
How do you produce a period report that reconciles to finance?
Report from the stamped values, per period, per currency, in a form finance can tick against their own ledger. Run it after period close from the same filters every time, and keep the output. The method for walking one disputed figure back from a report cell to source records is in our guide to dashboards that disagree with finance, and larger datasets that hit query limits are covered in our Dynamics 365 reporting limits guide.
- Filter on the governing date, not created on or modified on, and on the record states finance counts, such as fulfilled orders or posted invoices.
- Show totals in transaction currency per currency, the stamped rate or rates used, and the converted total, so a reviewer can recompute any line.
- List records with no stamp, a stamp outside the period, or a native base value that differs from the stamped conversion, as exceptions to explain.
- Compare the converted totals to the finance system of record and document each variance with its cause, such as timing, credit notes or rounding.
- Export the report and exception list at close and store them read-only with the date, the filters used and the person who ran it.
- Where the auditor needs to inspect records directly, see our guide to read-only access for external auditors.
What are the common multi-currency pitfalls in Dynamics 365?
Most multi-currency audit findings come from a handful of predictable causes. Check each one against your environment before the auditor does.
| Pitfall | What goes wrong | What to do |
|---|---|---|
| Wanting to change the base currency | The base currency cannot be changed after the environment is created | Keep base as is and report in another currency through stamped conversions, or plan a new environment and migration if base is fundamentally wrong |
| Rate changed mid-period | Records created before and after the change carry different rates, and edits move old records to the new rate | Stamp by governing date from the dated rate table instead of relying on the record rate |
| Recalculation on edit | Editing an amount after close changes base values in a closed period | Lock amounts and stamps for closed periods and route corrections through an audited adjustment |
| Rounding and precision | Currency precision, pricing decimal precision and line-level rounding make totals differ by small amounts from finance | Agree precision settings with finance, convert at the level finance does (line or total), and document the tolerance for rounding variances |
| Records created before the rate table existed | Old records carry whatever rate the Currency table held at creation, or at their last edit | Backfill stamps from historical rates by governing date in a one-off, logged run, and flag records that cannot be matched |
| Migrated records | Imported records take the rate current at import time, not the historical rate | Load historical rates into the dated table first, stamp during migration, and reconcile the migrated totals; see our legacy CRM data migration guide |
| Nobody owns the rates | The Currency table is updated irregularly by hand, or not at all | Load rates on a schedule from the source finance uses, under a service identity, with auditing on |
How does multi-currency fit into a Dynamics 365 Sales implementation?
Currencies, price lists per currency and the governing date rule are design decisions for the start of a Sales project, not something to retrofit before an audit, and they belong alongside the opportunity, quote and order process described on our Dynamics 365 Sales implementation page. Discounts applied on quotes and orders affect the amounts that get converted, and the options for them are in our volume discounts and tiered pricing guide.
Keep the boundary clear: the CRM holds the commercial record and a defensible conversion, and the finance system of record remains the source of truth for accounting. Solzet works on Dynamics 365 Customer Engagement and Power Platform and does not implement finance or ERP systems; we make the CRM side reconcile to whatever finance system you already run.
Is Dynamics 365 the right platform when currency controls matter this much?
For most sales teams, yes: the native model plus a dated rate table and stamping is a modest, well understood extension. We recommend the right solution - whether that's Microsoft Dynamics 365, Power Platform, or a custom-built CRM. Some businesses need the Microsoft ecosystem. Others need full control without licensing. We deliver both. If per-user Microsoft licensing does not fit, or you want full control over how every amount is stored and converted, a custom-built CRM on React, Node.js, PostgreSQL or .NET can hold dated rates and conversions exactly as your finance policy defines them, with no Microsoft licensing.
Should currency-sensitive sales data live in Dynamics 365 or a custom-built CRM?
Can afford licensing and want the Microsoft ecosystem
Dynamics 365
Microsoft 365, Teams and Outlook integration, a mature partner ecosystem, Copilot, and apps for sales, service and field operations that are configured rather than built.
Need full control and zero licensing
Custom CRM
A CRM built on React, Node.js, PostgreSQL or .NET that you own outright: your data model, your hosting, no per-user subscription, and features shaped exactly to your process.
Not sure which fits
We help you decide
A short discovery weighs licensing budget, process complexity, integrations and long-term ownership, then recommends one path. We deliver both, so the recommendation has no reason to lean.
How does Solzet help make Dynamics 365 currency figures audit-ready?
We start by testing how your environment actually behaves and comparing a sample period against finance, so the gaps are known before the auditor finds them. Then we agree the governing date rule with finance, build the dated rate table and scheduled rate load, add stamping and period locking logic with tests, backfill historical records in a logged run, and deliver the period report, exception list and a short evidence procedure your admin can run at each close.
The work is done by senior consultants and full-stack developers delivering remotely from Yerevan, Armenia, with 8+ years of Dynamics 365 Customer Engagement and Power Platform work, directly for your team or white-label for Microsoft partners. Broader development and integration work is described on our Dynamics 365 consulting page.
What do people ask us?
How does Dynamics 365 handle exchange rates on records?
Each record with currency columns stores its transaction currency, the exchange rate applied and a base currency value for every amount. The rate comes from the Currency table when the record is created and is refreshed when the record's currency or a currency amount is updated. Verify the current triggers in a test environment before relying on them.
Does changing an exchange rate in Dynamics 365 update existing records?
No. Updating a rate on the Currency table does not restate existing records; they keep the rate they already hold. A record picks up the new rate only when its currency or a currency amount is next updated, which is why edits after period close can move base values unexpectedly.
Does Dynamics 365 keep a history of exchange rates?
Not as a rate table. The Currency table holds one current rate per currency, overwritten on update. Auditing on that table records changes, but for audit evidence it is far more practical to keep a custom dated exchange rate table and stamp the rate used on each financial record.
Can I change the base currency in Dynamics 365?
No. The base currency is set when the environment is created and cannot be changed afterwards. If you need figures in another reporting currency, convert them with stamped rates from a dated rate table. If the base currency is fundamentally wrong, the remaining option is a new environment and a migration.
Why do Dynamics 365 currency totals differ slightly from finance?
Usually rounding and precision: currency precision, pricing decimal precision, and whether conversion happens per line or on the total. Different rates or dates are the other common cause. Agree precision and conversion level with finance, stamp the rate used, and document an accepted rounding tolerance for the period reconciliation.
Which date should govern the exchange rate for a CRM record?
The date your finance policy uses, applied consistently: typically the order date for orders, the invoice date for invoices and the close date for opportunities, with a defined fallback when no rate exists for that day. Take the rule from finance and match the finance system of record rather than inventing a CRM-only rule.
How do I fix exchange rates on records migrated into Dynamics 365?
Imported records take the rate current at import time. Load historical rates into a dated rate table, stamp each migrated record with the rate for its governing date during or after migration in a logged run, flag records that cannot be matched, and reconcile migrated totals per period against finance.
Does Solzet implement Dynamics 365 Finance for currency accounting?
No. Solzet works on Dynamics 365 Customer Engagement, including Sales, and Power Platform, and does not implement Dynamics 365 Finance, Business Central or other ERP systems. We make the CRM currency figures defensible and reconcilable to whichever finance system of record you already run.
Where should you go next?
Dynamics 365 Sales implementation
Opportunity, quote and order processes, price lists and forecasting designed around how your team sells.
Dynamics 365 audit trail for compliance
Enabling, scoping and retaining Dataverse audit history an auditor can rely on.
Dashboards that disagree with finance
Walk one figure from source record to report cell and fix the gap in the data model.
Volume discounts and tiered pricing
Where native discount lists stop and how to handle tiered pricing on quotes and orders.
Read-only access for external auditors
Giving auditors scoped, logged and revocable access to the records in scope.
Custom CRM Development
CRM on React, Node.js, PostgreSQL and .NET for organizations that need full control without Microsoft licensing.
Which solution is right for your business?
Tell us what you need. A senior consultant replies within one business day with a recommendation - Dynamics 365, Power Platform, or a custom-built CRM - not a sales script.