Multi-currency catalogs
(Section: Operations and Management)
1) Task and scope
A multi-currency catalog is a single source of truth about prices/fees/taxes for different currencies, regions and channels. It provides:- correct price mart (UX, trust),
- reproducibility of calculations (audits, returns),
- economic predictability (margin/taxes),
- compliance (taxation, sanctions, currency restrictions).
2) Data model (reference)
Entities:- Product/SKU: `{sku_id, title, attributes, region_policies[]}`
- PriceList: `{pricelist_id, base_currency, effective_from, effective_to, version}`
- PriceItem: `{sku_id, base_price, base_currency, tax_class, pricing_model, promo_refs[]}`
- FXRate: `{pair: EUR→USD, rate, source, method, precision, effective_from, version}`
- `minor_units` (ISO 4217; e.g. JPY = 0, USD/EUR = 2, KWD = 3; for crypto - up to 8)
- 'rounding _ mode ':' HALF _ UP '(retail),' BANKERS '(finance),' FLOOR '/' CEIL '(taxes/regulators)
3) FX sources and policy
Sources: course providers (commercial/central banks), own TWAP/median.
Update policy: frequency (1-15 min for volatile, 1 time/day for stable), publication delay.
Markups: 'rate (1 + fx_markup_bps)' to the client side; transparent per-channel/region rules.
Guaranteed quotation window (rate lock): 5-30 minutes with 'fx _ version' in the order.
Anti-jump: cap changes per tick, circuit-breakers, fallback on the latest valid quote.
Versioning: each course publication has a'version', 'effective _ from'; Keep history for returns/disputes.
4) Pricing strategies
Base + FX: store the base price in the "core" (for example, EUR), convert on the showcase.
Per-currency sheets: pre-calculated prices for key currencies (best UX, predictability).
Mixed: top 10 currencies - pre-calculation, "long tail" - on-the-fly.
Charm-pricing: `X. 99/95/90 'by region, monitor the accumulation of rounding errors.
Fees: payment fee, cross-border fee, network fee (crypto) - in the directory or at the "Checkout Pricing" stage.
5) Taxes and "inclusion"
VAT/GST included/excluded: EU - more often than VAT-inclusive; B2B can be VAT-free.
Layers of taxes: federal/state/local; for online games - specific fees.
Threshold rates: tax varies from turnover/category/region (threshold).
Tax rounding: per-item vs per-basket; rounding modes and calculation order must be deterministic.
Yur. reporting: keep the'tax _ rule _ version' in the check/receipt.
6) Rounding and accuracy
Round at the last step of the show; keep "high accuracy" in calculations (up to 8-9 characters).
For crypto, use decimal libraries (without binary floating point).
Basket anti-drift: "bankers rounding" for amounts, but UX-rounding for display; fix'rounding _ scope '.
Sum rule: the sum of line-by-line rounding must be the same as total - use penny distribution.
7) Catalogs, promos and bundles
Promo-правила: `if region=A and currency in [EUR,USD] then discount=10% cap=50`.
Order of application: (1) base price → (2) discounts → (3) taxes → (4) fees → (5) rounding.
Bundle distribution: proportional to the position tab before the discount; wrapper for returns.
Threshold promo: free shipping/bonus when total≥X in cart currency; Keep the base currency equivalent, but fix the FX version.
8) Integration with payments and compliance
Currency availability: Not every currency is available to every player/region/payment provider.
Guaranteed FX: authorization prefix by fixed 'fx _ version'; during expiration - request confirmation of the new price.
CUS/sanctions: block lists of currencies/banks/tokens, restrictions on conversion.
Returns/chargeback: recalculation according to the historical 'fx _ version' of the order; return fee - by directory on the date of the transaction.
9) API Architecture and Contract
Reading directory:- `GET /catalog/prices? sku=…¤cy=…®ion=…&pricelist=…`
- Ответ: `{unit_price, currency, fx_version, pricelist_version, tax_breakdown[], fees[], display_price, rounding_mode}`
- `POST /pricing/quote { items[], region, currency, buyer_type }`
- Ответ: `{items_priced[], subtotal, discounts, taxes[], fees[], total, fx_version, lock_ttl, signature}`
- 'POST/pricing/commit {quote_id, signature} '→ receipt with hash and signatures.
- `PriceListUpdated`, `FXRatePublished`, `TaxRuleChanged`, `PromoChanged` — с `version/effective_from`.
10) Caching and performance
Edge cache: key 'pricelist: region: currency: sku: version'; The TTL for stable currencies is higher.
Warmup: Warming up the top categories by campaign launch.
SWR (stale-while-revalidate): for storefronts; checkout - fresh only.
Partial invalidation: disability by 'sku', 'category', 'pricelist _ version' tags.
SLO: p95 ≤ 120ms for display, p95 ≤ 250ms for quote, ≥99. 95% availability.
11) Observability and audit
Trace: 'trace _ id', 'pricelist _ version', 'fx _ version', 'tax _ rule _ version' in all events.
Immutability: WORM-journals of publications of price lists/courses; Merkle-slices, release signatures (DSSE).
Receipts: check/receipt with full layout and payload hash; store for 7-10 years (by regulator).
Dashboards: vitrina↔checkout discrepancy, up/down rounding frequency, FX errors, course lock time (lock TTL), ROI promo.
12) Display localization
Currency format: character/code (₴, €, $, AED), character position, delimiters, space.
Local rules: "₴ 1,234,56" vs "$1,234. 56”.
Psychology: magic price tags ('.99') are not always appropriate in fintech/games; test the per-region.
Legal signatures: "Price includes VAT," "Network commission is charged separately."
13) Special cases
Currencies without fractional part: JPY/ISK - minor_units=0.
Three-character minor units: KWD/BHD = 3.
Crypto: BTC/ETH/USDT - up to 8 characters, network fee separately; stablecoins ≠ "1:1 heading" with cross border.
Double price: "catalog currency" ≠ "write-off currency" (merchant bank rate). Document the spread.
Sports/games: maximum winnings limits in catalog currency - keep equivalents by 'fx _ version' round.
14) SLO/SLI and success metrics
Correctness: the proportion of orders where total_checkout = total_quote (± 1 minor unit for distribution rules) ≥ 99. 99%.
FX stability: the share of operations in the rate lock window ≥ 99%.
Economy: margin/unit vs plan; deviations due to FX/rounding (bps).
UX: speed quote p95, share of dumps on price conversion, NPS storefronts.
Audit: 100% of checks with saved '_ version' and signature.
15) Incident playbooks
"The price on the showcase ≠ in the basket":1. freeze cash disabled, 2) forced refresh price list, 3) compare 'pricelist _ version '/' fx _ version', 4) policy compensation.
"FX jump destroys margins":1. enable increased markup/discount cap, 2) reduce lock TTL, 3) switch to fallback source.
"Tax does not converge":1. check 'tax _ rule _ version', 2) validation of rounding_scope, 3) hotfix rules and reprice of baskets.
"Promo gives a negative price":1. security rules (min_price), 2) disable stacking, 3) recalculation and audit.
16) Safety and compliance
Policy-as-code: control of changes in price lists/FX/taxes through PR + release signatures.
Roles/accesses: 4-eye principle on price publications/FX.
Logs/receipts: signed publishing events and checkout.
Regional restrictions: prohibition of individual currencies/tokens; geo-politicians.
17) Experiments and optimization
A/B: charm-pricing, pre-calculated prices vs on-the-fly, display format.
Dynamic markup: dependence on pair volatility/time of day.
Cohort analysis: returns/chargeback by currency, rounding sensitivity.
Cash strategies: SWR/TTL impact on conversion and accuracy.
18) Implementation checklist
- Define the base currency and policy per-currency of the sheets.
- Configure FX collection/publishing with versioning, markups, and lock TTL.
- Formalize TaxRule and calculation/rounding order (per-item or per-basket).
- Implement directory API/quote/commit + signed receipts.
- Enable edge cache and granular disability; SWR for storefronts.
- Create dashboards (vitrina↔checkout, FX errors, taxes, bps margin).
- Enter roles/signatures on price/rate publications, WORM journals.
- Prepare playbooks: Price miss, FX spike, tax discrepancies.
- Conduct "GameDay Catalog": disable FX source, promo burst, tax change.
- Regularly revamp minor_units/otobrazheniye by region.
19) FAQ
Do I need to store prices in each currency?
Not necessarily. Combine pre-calculation for top currencies and conversion for tail - this is how UX and costs are balanced.
Why does total "not beat" after rounding?
Due to differences per-item vs per-basket. Fix one approach and use "penny distribution."
How to make a refund in a month?
According to the historical 'pricelist _ version', 'fx _ version' and 'tax _ rule _ version' stored in the receipt.
What about crypto?
Use decimal accuracy, network fee separately, do not promise 1:1 to fiat; fix the course and the action window.
Summary: A multicurrency catalog is a combination of precision math, strict policies, and smart caching. Version everything (prices/rates/taxes), fix the quotation window, determine the order of calculations and rounding, sign check artifacts and keep dashboards visible. So you get an honest showcase, reproducible settlements and a managed economy in all currencies and regions.