Overview / Ledger / money
ADR 0032
Currencies hard-partition balances; no in-ledger FX; rates from cached external APIs
AcceptedLedger / money
Context
Merchants transact in multiple currencies. Two questions follow: does a single balance mix currencies (with implicit conversion), and where do exchange rates come from when a rate is needed for display or quoting?
Decision
Hard-partition balances by currency and keep all FX out of the ledger; source rates for display/quoting from external rate APIs behind a layered cache.
- One wallet per currency. A merchant holds a separate wallet per currency (ADR 0031); an amount is only ever posted to its own-currency wallet. The ledger never converts one currency into another — there is no implicit FX movement in the system of record.
- FX is display/quote-time only. When a rate is needed (showing an approximate price, quoting a cross-currency figure), it is fetched from external exchange-rate APIs and cached in Redis; it never silently rewrites a stored balance.
Consequences
- Positive: every currency's balance is exact and independently auditable; there is no rounding or hidden spread buried inside a ledger conversion.
- Neutral / to revisit: anything genuinely cross-currency (e.g. paying out in a different currency than was collected) needs an explicit conversion step outside the ledger, booked as its own movements — there is no one-balance shortcut.
- Neutral / to revisit: FX depends on an external provider and a cache; the platform currently has more than one FX code path and an externally-hosted rate dependency (a hardcoded rate-API key in production is a known hygiene issue to remediate — it is operational debt, not part of this decision).
Alternatives considered
- A single multi-currency balance with in-ledger conversion: rejected — implicit FX inside the ledger makes balances inexact and conversions un-auditable; partitioning keeps each currency's truth clean.
- A self-hosted / contracted FX rate feed: not adopted — cached external APIs are cheaper for display-grade rates; the trade-off is an external dependency and key hygiene, acceptable because FX never drives a ledger movement.