GH GambleHub

per currency directories

The per currency catalog is a variant of the content catalog and pricing where displayed prices, limits, bonuses, minimum bets, jackpots, and promo texts are tailored to the player/tenant/region currency. The goal is to give the right price points and rules without copying logic and without risks due to on-the-fly conversions.

Key effects:
  • UX: natural rate steps and "beautiful" prices (₺9. 99, R$5, €0. 20).
  • Income: exact limits and boosts without "eating through" margins due to courses.
  • Compliance: compliance with local rules (licenses, taxes, age/geo).

1) Data model: separate "nominal" and "representation"

Base Price (nominal): single local currency'PLN '/' EUR '/' USD'for settlements.
Display Price - calculated from face value + FX + rounding + spread/fees.
Policy: rounding rules, betting steps, min/max limits, jackpots, bonus amounts and wager - set per currency.

Mini-diagram (simplified):
yaml price_model:
base_currency: "EUR"
items:
game_spin_min:
base: 0. 10 policy: "stake_min"
game_spin_step:
base: 0. 10 policy: "stake_step"
jackpot_seed:
base: 10000 policy: "jackpot_amount"
policies:
stake_min:
per_currency:
EUR: {round: "ceil_to_step", step: 0. 10}
TRY: {round: "ceil_to_step", step: 1. 00}
BRL: {round: "ceil_to_step", step: 0. 50}
stake_step:
per_currency:
EUR: {step: 0. 10}
USD: {step: 0. 10}
CLP: {step: 50}
jackpot_amount:
per_currency:
EUR: {round: "nearest_100"}
MXN: {round: "nearest_1000"}

2) Source of courses (FX) and "freshness"

FX service is a single point of truth for conversions:
  • Course provider: main and reserve; refresh rate (for example, every minute for volatile, every 15 minutes for stable).
  • Bounded staleness: SLA "courses not older than Δ t" (for example, p95 ≤ 5 min).
  • Spread and commissions: configured per tenant/region/currency.
  • Freeze windows: "freeze" courses for the match/tournament/promo windows so that the price does not "jump."
  • Audit: Log FX versions with'valid _ from/valid _ to'to play checks.
Example of FX issuance:
json
{
"as_of":"2025-10-31T12:00:00Z",
"base":"EUR",
"rates": { "TRY":34. 10, "BRL":5. 42, "MXN":19. 1, "UAH":43. 6, "USDT":1. 00 },
"spread_bps": { "TRY":120, "BRL":60 },
"fees_pct": { "default":0. 15 }
}

3) Rounding and "beautiful" price points

Round after FX and spreads:
  • Prices/packages: '99', '9. 99`, `4. 90 '(psychological points).
  • Rates and steps: "ceil_to_step" to the currency step (₺1, CLP $50).
  • Bonuses: rounding down to voucher step (R $1/ ₺5).
  • Order of operations: 'raw = base fx (1 + spread) (1 + fee)' → 'rounded = round_policy (raw) '→' min/max clamp '.

Anti-example: "bank rounding" for rates can give "ugly" steps - use explicit policies.

4) Limits, min/max and jackpots

Min/Max per currency-Consider local laws and RGS constraints.
Jackpots: If the provider is holding a jackpot in their currency (e.g. EUR), show either a localized equivalent (informer) or keep per-currency pools.
Currency steps: CLP/JPY without kopecks - all limits are integer.

Example of a limit table:
sql
CREATE TABLE currency_limits (
tenant_id text,
currency  text,
feature  text,  -- spin_min, spin_max, deposit_min, payout_max, jackpot_min value   numeric,
step    numeric,
PRIMARY KEY (tenant_id, currency, feature)
);

5) Bonuses and vouchers per currency

Bonus value: configured per currency (not "recalculation" in the forehead).
Wager: store as a multiplier (x30) or as a currency amount; avoid mixing.
Win cap/cash out: also per currency.
Marketing texts: number localization and currency in templates without hardcode.

yaml bonus:
welcome_pack:
EUR: {amount: 100, wager_x: 35, cap: 500}
BRL: {amount: 500, wager_x: 40, cap: 2500}
TRY: {amount: 2500, wager_x: 40, cap: 12500}

6) Provider restrictions (RGS/PSP)

RGS: some games are not available for 'crypto '/local currencies; some providers require fixed minimums (for example, €0. 20).
PSP: payment methods depend on currency (PIX ↔ BRL, PayID ↔ AUD, Papara ↔ TRY); deposit/withdrawal limits are also different.
Rule: Catalog/storefront filters games and payment methods by currency and jurisdiction prior to display.

7) Architectural outline

Currency Policy Store (CP) - rule tables per currency (steps, limits, price points, rounding).
FX service: cache of courses, versions and SLA freshness.
Catalog builder: produces Read Models per currency (projections).
Reading Layer API: extrudes finished projections; no on-the-fly conversions in the UI hot track.
Outbox → Projections: FX/policy changes → 'CurrencyPolicyUpdated/FXUpdated' events → incremental window updates.

Projection section diagram:

read_catalog_{tenant}_{region}_{currency}

Currency partitioning speeds up refresh and metric collection.

8) Projections per currency (example)

sql
CREATE TABLE read_catalog_currency (
tenant_id  text,
region   text,
currency  text,
game_id   text,
price_min numeric, -- displayed min-rate price_step numeric,
jackpot   numeric,
bonus_badge text,
as_of    timestamptz,
PRIMARY KEY (tenant_id, region, currency, game_id)
);

Updates - idempotent'UPSERTS 'from directory events + FX events/policies.

9) Formatting and locales

Symbol/code: '₺/TRY', 'R $/BRL', '€', 'USDT' (for crypto - without kopecks or with 2 characters, according to UX policy).
Grouping and decimal separator: depend on 'locale' (ru_RU, tr_TR, pt_BR).
RTL/Arabic locales: a separate check for the correctness of the currency sign.

10) Caching and performance

Cache catalog responses per currency for 30-120 s; Give the FX indicator 'as _ of' in the response.
Disabled: 'FXUpdated '/' PolicyUpdated '/' GameUpserted' events → targeted cache key flush.
Pagination with cursors so that the order of the cards does not "jump" with small price updates.

11) Observability and SLO

Metrics:
  • `catalog_p95_ms` по валютам, `fx_freshness_ms` (p50/p95/p99), `policy_refresh_latency_ms`.
  • Share of "ugly" prices (do not lie on the step), share of rejected transactions due to limits.
  • Discrepancy "showcase vs calculation" on the check-out (where the real debit occurs).
Alerts:
  • FX older than SLA, increase in rounding errors, surge in PSP limits failures.
  • RGS minimum and display minimum mismatch.

12) Compliance, taxes and residency

Per currency ≠ per country: follow the combination of'currency + geo + license'.
Tax rules/fee - in the currency policy and in the check.
Residency: data and calculations for local currencies - in the corresponding region.

13) Testing

Property-based: invariant "after conversion and rounding, the price lies on the step"; «min ≤ value ≤ max».
Golden-cases: set of reference currencies/prices for regression.
Chaos FX: "jumping" courses, freeze windows, switching FX provider.
E2E: matchability of the amount on the showcase and the total amount written off; tolerance ≤ 0. 01 currency units (or 1 step).

14) Typical errors

Recalculate on the fly to the read API → unstable UX and high p99.
Ignore currency moves (CLP/JPY) → half a penny and RGS/PSP failures.
Round out of habit (bankers rounding) instead of clear rules per policy.
It is → impossible not to fix the FX version in the check to sort out disputes.
Single bonus denominations via FX → "strange" numbers for local markets.
Hiding fees in FX without transparency is a risk of claims and fines.

15) Quick recipes

Bets in TRY/BRL: step ₺1/R $0. 50, min-rate round up to the step, "beautiful" price points for packages.
Crypto (USDT/USDC) step $0. 10, rounding to the nearest step, no commissions in the show (but visible in the check).
High-volatility FX: freeze for match/promo; alerts at> X% of base price.
Multi-tenant: different spreads/steps in brands; fairness in projection calculations per tenant.

16) Configuration example (single source of truth)

yaml catalog_currency:
base_currency: EUR fx_sla_ms: 300000 # 5 minutes rules:
- currency: "TRY"
stake_step: 1. 00 stake_min: 5. 00 display_round: "ceil_to_step"
psychological_points: [9, 19, 29, 49, 99]
psp_methods: ["Mefete","Papara","Crypto"]
- currency: "BRL"
stake_step: 0. 50 stake_min: 1. 00 display_round: "ceil_to_step"
psychological_points: [4. 90, 9. 90, 19. 90, 49. 90]
psp_methods: ["PIX","Boleto","Cards"]
- currency: "CLP"
stake_step: 50 stake_min: 200 display_round: "ceil_to_step"
psp_methods: ["WebPay","Cards"]
jackpot:
display_policy:
EUR: "nearest_100"
MXN: "nearest_1000"
bonuses:
welcome:
EUR: {amount: 100, wager_x: 35}
BRL: {amount: 500, wager_x: 40}
TRY: {amount: 2500, wager_x: 40}

17) Pre-sale checklist

  • Single base currency and FX version in each check/event.
  • Rounding/step/limit policies are set per currency and covered by tests.
  • Directory projections per currency are ready; hot way does not convert.
  • Jackpots and bonuses are correctly displayed/dripped per currency.
  • PSP methods are filtered by currency; limits coincide with the showcase.
  • FX freshness SLAs and alerts are configured; freeze windows for volatile events.
  • Localization of currency numbers and symbols; non-hardcode promo templates.
  • Audit policy changes/FX; check reproducibility.
  • Multi-tenant/region: data isolation, different spreads and limits.
  • Incident playbooks: FX jump, RGS minimum mismatch, PSP limit failure.

Conclusion

per currency catalogs are an engineering discipline, not "multiply by course." Separate denomination and representation, centralize FX and rounding policies, materialize projections per currency, and measure freshness. Then the showcase will be fast, predictable and honest, and the business will be protected from hidden margin losses and regulatory surprises in local markets.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.