Operator guideEN

Transactions / Casino

Game transaction dashboard with real-time list mode, monthly analytics mode, filterable table, and a dedicated transaction detail route.

How to use this guide

Start with the main guide

Follow the explanation and examples first. Extra definitions and formulas are available below when you need them.

What this surface shows

Transactions / Casino is the Backoffice work surface for game transaction rows such as bets, wins, rollbacks, and free spins.

It combines:

  • a real-time table view
  • a monthly analytics view calculated from the loaded row data
  • filter controls
  • summary cards derived from the loaded rows

Use it when you need to inspect how gaming transactions are distributed by game, provider, player, action type, or time.

How to read it

The page has two modes:

  • Real-Time View
  • Monthly Analytics

In Real-Time View, the main operator surface is the table. The rows come from the casino transaction row source. The cards above the table summarize the currently loaded row set, not a separate full-result aggregate.

In Monthly Analytics, the page uses the same casino-transactions list request in analytics mode and then derives monthly charts, provider shares, status distribution, and headline cards from those rows. The mounted page does not use a separate monthly aggregate route.

The table helps answer:

  • which player performed the transaction?
  • which game and provider are involved?
  • was this a bet, win, rollback, or free spin?
  • what was the real amount versus bonus amount?

Filters that change the list

The visible filters are:

  • Search email
  • Currency
  • Type
  • Status
  • Provider
  • Date start
  • Date end

Server-side filtering is applied before the page calculates cards or analytics. Date, status, email, user, currency, transaction type, provider, and transaction id filters are translated into the row query first.

Common questions

Does this page show banking transactions?

The mounted list route is for casino-side game transaction rows. The row source also supports a unified financial-events mode for other callers, but this screen does not pass includeFinancialEvents=true, so the standard operator page does not mix banking rows into the table.

Why do the top cards change when I change the table filters?

Because the summary cards are calculated by the page from the loaded transaction list. Total Transactions uses the loaded row count, while the table badge and pagination use the full filtered result count.

Why can email search pull older rows than the selected date range?

Because the list hook resets startDate to 2022-01-01 whenever email is non-empty. In practice, email search intentionally widens the time window beyond the currently selected dates.

Why do the status filter values differ from the row badges?

Because the filter sends string values like pending, completed, failed, and rollback, while the loaded row data stores numeric status codes that the page maps to Pending, Complete, Failed, and Rollback.

What is the difference between Monthly Analytics and the table?

The table is row-level inspection. The analytics mode is a chart/report view derived from a wider list request. It is useful for directionality, provider share, and status distribution, but it is not a separate finance/reporting aggregate.

Known caveats

  • The real-time cards convert bet/win/average amounts to EUR using the current currency list. EUR rows are used as-is; non-EUR rows are divided by the currency exchange rate when available; rows with a missing rate fall back to the original amount. If the currency list is not loaded yet, those card sums can be temporarily incomplete.
  • The real-time card display currency is hard-coded to EUR after conversion.
  • Monthly Analytics uses raw row amounts in the row currency and then formats chart values with the most common row currency. Do not compare those chart amounts directly to the real-time EUR cards without checking currency mix.
  • The analytics header says Last 3 Months, while the headline card label says Total Transactions (6 Months). The traced hook default builds the analytics request and month buckets with a 3-month analysis window unless a different monthsToAnalyze value is passed.
  • Average Monthly Profit divides analytics profitLoss by 6, even though the default analytics buckets are 3 months. Treat it as the mounted page formula, not a full-period monthly average.
  • Status Health searches for an analytics status label named Complete. Standard rows expose numeric status codes, and the analytics reducer can keep those as string keys such as 1, so the card can show 0% even when completed rows exist.
  • The dedicated detail route is /transactions/casino/[transactionId].
  • The row component also has an expandable inline details panel, so operators currently have both inline and routed detail patterns on this surface.
  • CSV export calls the same row service with csvDownload=true. The custom export is visible only for the wincraft theme and adds bet/win timestamp helper columns.

The row source, filters, CSV export, sanitizer, summary cards, and monthly analytics formulas have been traced. Summary cards and monthly analytics are display calculations from returned rows, so they should be read as page-level summaries rather than independent finance aggregates.

More details

Definitions and formulas

Open only the section you need. The relevant section opens automatically when you request help for a specific item on screen.

Display calculations14 topicsOpen details

Total Transactions

How It Works
`transactionsList.length`.
What To Check
Counts only loaded rows, not the full `transactionDetail.count`.

Total Bets

How It Works
`sum(convertToEUR(row.amount))` for loaded rows where `row.actionType === 'bet'`.
Currency Basis
EUR rows are added as-is. Non-EUR rows are divided by `currency.exchangeRate` when the currency list has a rate. Missing row rate falls back to original amount. If the currencies hook has not loaded, rows contribute `0` during that render.

Total Wins

How It Works
`sum(convertToEUR(row.amount))` for loaded rows where `row.actionType === 'win'`.
Currency Basis
Same display EUR conversion rule as Total Bets.

Profit/Loss

How It Works
`total_bet_amount_eur - total_win_amount_eur`.
What To Check
Positive means loaded bet amount is higher than loaded win amount after display EUR conversion.

Average loaded amount

How It Works
`sum(convertToEUR(row.amount) for loaded rows) / transactionsList.length`.
What To Check
Used internally in the statistics object but not mounted as a visible card in the current table header.

Realtime sparkline grouping

How It Works
Rows are grouped by `new Date(row.createdAt).toLocaleDateString()` and reduced into bet, win, count, and profit arrays.
What To Check
Date grouping uses browser locale date, while table timestamp display uses the UTC helper.

Monthly Analytics request window

How It Works
`TransactionsGamingAnalytics` passes `useTransactions(analyticsParams, true)`. The hook defaults `monthsToAnalyze` to `3`, then sets the request `startDate` to `subMonths(new Date(), monthsToAnalyze)`.
What To Check
The component's 6-month `analyticsParams.startDate` is overridden by the hook default when analytics mode is enabled.

Monthly Analytics buckets

How It Works
Hook creates month buckets from `subMonths(now, monthsToAnalyze - 1)` to the current month, then increments transaction count and raw amount totals by action type (`bet`, `win`, rollback-containing actions, and `freespins`).
What To Check
Analytics reducer uses raw row amounts and does not apply the realtime EUR conversion.

Provider distribution

How It Works
Rows are grouped by `providerName || 'Unknown'`; percentage is `providerRowCount / totalTransactions * 100`; results are sorted by row count descending and sliced to the top 5 providers.

Status distribution

How It Works
Rows are grouped by `transaction.status`; percentage is `statusRowCount / totalTransactions * 100`.
What To Check
Numeric source statuses become string object keys in the reducer, so the current label mapping can leave labels as `0`, `1`, `2`, and `3`.

Status Health

How It Works
Card reads the percentage of the analytics status distribution entry whose label is exactly `Complete`; if none exists, it displays `0%`.
What To Check
On standard numeric source rows this can show `0%` even when completed rows exist.

Average Monthly Profit

How It Works
`analyticsData.totalMetrics.profitLoss / 6`.
What To Check
Divisor is hard-coded to 6, while the default analytics bucket count is 3 months.

Bet/Win Ratio

How It Works
`totalBetAmount / totalWinAmount` when total wins are positive, otherwise `0`.
What To Check
Uses raw analytics row amounts, not realtime EUR-converted card amounts.

Email search date reset

How It Works
When `email` is non-empty, the hook forces `startDate = 2022-01-01`.
What To Check
Email search intentionally widens the query beyond the visible selected start date.
Source calculations7 topicsOpen details

Standard casino transaction row source

How It Works
The source loads the casino transaction query, applies the generated filters and ordering clauses, and queries `casino_system.casino_transactions` joined to wallets and non-deleted users. Game, provider, and aggregator labels are resolved by subqueries against `casino_system.master_casino_games`, `casino_system.master_casino_providers`, and `casino_system.master_game_aggregators`.
What To Check
This is the row source for the mounted Casino Transactions page.

Source count

How It Works
`transactionDetail.count` is produced by a count query over the same joins and dynamic `WHERE` clause as the row query.
What To Check
The table badge and pagination use this count; top cards use loaded rows.

Status filter mapping

How It Works
`pending -> 0`, `completed -> 1`, `failed -> 2`, and `rollback -> 3` through source status mapping.
What To Check
The visible filter uses strings, but standard source rows carry numeric status values.

Action type filter mapping

How It Works
`bet`, `win`, `rollback`, `rollbackbeforebetwin`, and `freespins` are validated by the source. The `rollbackbeforebetwin` filter maps through the shared `ACTION` constants to the stored pre-rollback action value.
What To Check
Financial event filters such as deposit/withdraw require unified history mode and are not sent by this mounted list.

Provider filter

How It Works
When `providerId` is selected, the source filters `game_identifier` through `casino_system.master_casino_games` rows whose `master_casino_provider_id` matches the selected provider.
What To Check
Provider filtering is applied before the display summaries are calculated.

CSV export

How It Works
CSV export calls the same service with `csvDownload=true`. Standard export uses the sanitized row keys as CSV fields. Custom export `customExport=win-timestamps` adds `Bet Time` and `Win/Credit Time`.
What To Check
Custom export is visible only when the casino theme is `wincraft`.

Numeric response sanitizer

How It Works
The source replaces `NaN`, `Infinity`, and `-Infinity` sentinels in amount, balance, primary-currency amount, and conversion-rate response fields with `null`.
What To Check
This protects the page from non-finite numeric display values.
Columns13 topicsOpen details

ID

User email

Game identifier

Game name

Provider

Row cell can also append `aggregatorName` in parentheses.

Note
Row cell can also append `aggregatorName` in parentheses.

Type

Display Mapping
Bonusactivation: Bonus Activation | Bonusclosure: Bonus Closure | Bonusaction: Bonus Action | Bonuswin: Bonus Win | Freespins: Free Spin | Rollbackbeforebetwin: Pre RollBack

Amount

Data Type
amount
Display Rule
Withdraw, withdrawal, and bonusclosure are displayed as negative absolute values; deposit, win, bonuswin, and bonusactivation are displayed as positive absolute values.

Bonus amount

Data Type
amount

Real amount

Data Type
amount

Currency

Status

Row component can also use `statusEnum` when unified financial rows are supplied by another caller.

Display Mapping
0: Pending | 1: Complete | 2: Failed | 3: Rollback | 4: Rollback | 5: Complete | 6: Rejected | 8: Expired
Note
Row component can also use `statusEnum` when unified financial rows are supplied by another caller.

Date

rendered with UTC hint in the table header

Note
rendered with UTC hint in the table header

Inline details

Filters7 topicsOpen details

Search email

Type
text
Behavior
Hook forces `startDate = 2022-01-01` whenever email is non-empty.

Currency

Type
select

Type

Type
select
Options
0: Label: All | 1: Label: Bet | Value: bet | 2: Label: Win | Value: win | 3: Label: RollBack | Value: rollback | 4: Label: Pre RollBack | Value: rollbackbeforebetwin | Backend Value: prerollback | 5: Label: Free Spin | Value: freespins

Status

Type
select
Options
0: Label: All | 1: Label: Pending | Value: pending | Backend Value: 0 | 2: Label: Complete | Value: completed | Backend Value: 1 | 3: Label: Failed | Value: failed | Backend Value: 2 | 4: Label: RollBack | Value: rollback | Backend Value: 3

Provider

Type
select
Backend Behavior
Filters game identifiers through `casino_system.master_casino_games` for the selected provider.

Date start

Type
date
Default
NUMBER_OF_DAYS_BEFORE before current date

Date end

Type
date
Default
current date
Summary cards4 topicsOpen details

Total Transactions

Formula Owner
page
Source Scope
Current returned rows after filters and pagination.

Total Bets

Formula Owner
page
Currency Basis
EUR conversion through the current currencies list.

Total Wins

Formula Owner
page
Currency Basis
EUR conversion through the current currencies list.

Profit/Loss

Formula Owner
page
Currency Basis
EUR after the same display conversion used by Total Bets and Total Wins.
View modes2 topicsOpen details

Real-Time View

Row-level casino transaction list with source pagination and page-level summary cards.

Monthly Analytics

Analytics view derived from the same casino transaction list endpoint.

Metrics8 topicsOpen details

Total Transactions

Count of loaded transaction rows in the current real-time result set.

Aliases
casino transaction count, total game transactions
Source Basis
Backend returns `transactionDetail.count` and `transactionDetail.rows` from `casino_system.casino_transactions` joined to wallets, users, game, provider, and aggregator lookups. The card counts the rows loaded into the page after the hook response.
Filter Dependencies
email, currency_code, transaction_type, status, provider, start_date, end_date

Total Bets

Sum of loaded `bet` rows after page-level EUR conversion.

Aliases
total bet amount, casino bets eur
Source Basis
Row source is `CasinoTransaction.amount` where `action_type` maps to `bet`.
Display Rules
Rows with `actionType === 'bet'` are included., If `currencyCode === 'EUR'`, amount is added as-is., If a currency exchange rate exists, amount is divided by `currency.exchangeRate`., If the row currency has no exchange rate, original amount is used., If the currencies hook has not loaded, the row contributes `0` during that render.
Currency Basis
Display Currency: EUR | Rate Source: Current currencies list loaded by the page. | Rounding: Display formatting only; reducer does not round before display.

Total Wins

Sum of loaded `win` rows after page-level EUR conversion.

Aliases
total win amount, casino wins eur
Source Basis
Row source is `CasinoTransaction.amount` where `action_type` maps to `win`.
Display Rules
Rows with `actionType === 'win'` are included., If `currencyCode === 'EUR'`, amount is added as-is., If a currency exchange rate exists, amount is divided by `currency.exchangeRate`., If the row currency has no exchange rate, original amount is used., If the currencies hook has not loaded, the row contributes `0` during that render.
Currency Basis
Display Currency: EUR | Rate Source: Current currencies list loaded by the page. | Rounding: Display formatting only; reducer does not round before display.

Profit/Loss

Difference between converted total bet amount and converted total win amount in the current loaded row set.

Aliases
casino pnl, betting profit loss
Source Basis
Uses source-provided row amounts; subtraction is owned by the page display.
Display Rules
`profitLoss = totalBetAmount - totalWinAmount` after the same EUR conversion used by the bet and win cards.
Currency Basis
Display Currency: EUR | Rate Source: Current currencies list loaded by the page.

Total Transactions (6 Months)

Count of rows returned for analytics mode.

Aliases
casino monthly analytics total transactions
Source Basis
Same list source as realtime mode.
Display Rules
Mounted component passes analytics mode through `useTransactions(analyticsParams, true)`., Hook default `monthsToAnalyze` is 3; it overrides the component's 6-month start date when building the query., `totalMetrics.totalTransactions = transactions.length`., `growthRate = ((currentMonth.transactionCount - previousMonth.transactionCount) / previousMonth.transactionCount) * 100`, or `0` when the previous month count is not positive.
Caveats
Visible label says 6 months, but traced hook default produces a 3-month analytics request/bucket set unless a different `monthsToAnalyze` is passed.

Average Monthly Profit

Page-derived `profitLoss / 6` card shown in monthly analytics mode.

Aliases
casino average monthly profit
Source Basis
Same list endpoint and raw row amounts as analytics mode.
Display Rules
`totalMetrics.profitLoss = totalBetAmount - totalWinAmount` over analytics rows., Card displays `analyticsData.totalMetrics.profitLoss / 6`., Analytics amount reducers use raw `Number(transaction.amount)` and do not apply the realtime EUR conversion.
Currency Basis
Display Currency: Analytics `mostUsedCurrency`. | Rate Source: No FX conversion in analytics reducer.
Caveats
Divisor is hard-coded to 6 even when the default analytics buckets are 3 months., Do not compare directly to realtime EUR cards when multiple currencies are present.

Top Provider

Provider with the highest transaction count in the derived analytics dataset.

Aliases
casino top provider
Source Basis
Provider label comes from the provider-name lookup in the row source.
Display Rules
Rows are grouped by `providerName || 'Unknown'`., `percentage = providerTransactionCount / totalTransactions * 100`., Providers are sorted by transaction count descending and sliced to the top 5.

Status Health

Page-derived completion-rate card based on analytics status distribution.

Aliases
casino completion rate, casino status health
Source Basis
Standard row status source is `CasinoTransaction.status` from the list query.
Display Rules
Analytics status distribution counts rows by `transaction.status`., Card reads the percentage where `statusDistribution.status === 'Complete'`.
Caveats
Object keys from numeric source statuses are strings in the reducer; the current label switch handles numeric `1`, not string `'1'`. On standard rows this can leave labels as `'0'`, `'1'`, etc. and make Status Health display `0%`.
More help

Related pages

Transactions / Banking

Filterable banking transaction dashboard with weekly summary cards, backend stats charts, CSV export, and a detailed ledger-style table.

Transactions / Casino Transaction Detail

Read-only detail page for a single casino transaction identified by `casinoTransactionId`.

Transactions / Failed Deposit

Triage grid for failed deposit rows, provider failure reasons, normalized error groups, raw detail inspection, and CSV export.

Transactions / Failed Deposit Error Groups

Configuration surface for creating, editing, importing, exporting, and assigning failed-deposit error groups and their reasons.

Transactions / KYC

Action-heavy KYC document queue exposed under the transactions area for document review, verification, re-request, download, and third-party checks.

Transactions / Shared Detail Modals

Reusable read-only transaction payload modals for banking-style rows on banking, withdrawals, and failed-deposit surfaces.