Currency Management
Canonical Rules
- Currency codes must be ISO-4217, 3 letters, uppercase.
Site.currencyis the canonical fallback source.- Default fallback is
EURwhen currency is absent or invalid. Product.currencyis required for catalog, widget, and search rendering.- FX conversion is intentionally out of scope. Values are never auto-converted between currencies.
- Mixed-currency monetary data must not be merged into one scalar total.
Data Model
Site.currency(required, defaultEUR)Product.currency(required, backfilled from site currency where missing)- Legacy defaults that were
USDwere normalized toEURin v2 rollout.
Fallback Order
Use this order for runtime and forwarding decisions:
- Event-level currency (if valid)
- Order-level currency (if valid)
- Site-level currency (
Site.currency) EUR
API Contract Notes
POST /api/v1/sitessupportscurrency.PUT /api/v1/sites/:idsupportscurrency.PUT /api/v1/admin/sites/:idsupportscurrency.- Product responses include mandatory
currency. - Category conversion analytics return
revenueByCurrency[](no mixed single total).
Analytics Rules
- When multiple currencies exist in a window, responses expose per-currency rows.
- UI must format each amount with the row currency.
- Dashboards should show
Mixedfor aggregate cards when a single-currency total is not valid.
Integration Forwarding Rules
- GA4 / Meta / Google Ads currency resolution uses the fallback order above.
- Provider payloads should not default to
USDunless explicitly set by event/order/site data.
UI Rendering Rules
- Never render fixed symbols (
$,€,₺) without a currency code context. - Use shared currency formatter utilities.
- Do not concatenate symbol + numeric strings manually.
Guardrail
- Run
pnpm currency:checkto catch hardcoded fallback currency and symbol regressions in runtime code.