Skip to content

Stakes and money

A stake is the amount associated with a bet. A win multiplier is a ratio. Keep these values separate.

Units

ValueUnit and interpretation
stake, balances, amountToCollect, amountCreditedInteger units of 1/100 of the account currency. For EUR, 100 means EUR 1.00.
Reply config.stakes, config.minStake, config.maxStakeAmounts after the engine applies the currency multiplier. Do not multiply them again.
Reply gameSettings.minStake, maxStake, maxPackageStake, maxExposureAmounts after the RGS applies the currency multiplier.
gameSettings.customStakesExplicit amounts in 1/100 of the game currency. The RGS applies no multiplier to them. They replace the default ladder.
config.currencyMultiplierConversion of authoring amounts into the account currency. This is not a display divisor.
IGameResult.totalWin, engineData.bankedWinMultipliers of the round's original base stake.
Slot scenario.winAmount, win breakdownsMultipliers for presentation. They are not separate wallet credits.
buyFeatures[].priceMultiplier of the selected base stake.
rtp, featureRTPPercentages. 95.5 means 95.5%, not 0.955%.
maxWin, maxPayoutMultipliers. The first describes one spin. The second describes the whole round.
maxWinOdds, maxPayoutOddsThe N in “1 in N”. See the known limitation.

For custom and social currencies, use the operator's display label and precision contract. Keep wire amounts unchanged. See Currencies.

The engine applies this precedence:

  1. A nonempty gameSettings.customStakes list replaces the game ladder.
  2. Without that list, operator min/max settings replace the corresponding game defaults.
  3. The engine applies the currency multiplier to game defaults before comparison.
  4. A game ladder with more than one entry also restricts accepted values.

loadConfig supplies effective min/max values on current engines. Its ladder can exclude stakes that exceed maximum exposure.

Custom stakes bypass engine bounds

Current validateStake skips min/max checks when customStakes is nonempty. Server acceptance does not prove a custom stake meets jurisdiction limits. Apply approved limits in the frontend. Resolve a conflicting configuration before release.

Build the frontend list from the custom ladder, or otherwise config.stakes. Remove duplicates, nonpositive values, and invalid amounts. Apply the approved bounds for this player, currency, and vertical.

Use operator overrides when computing effective bounds. Do not intersect an operator override with an obsolete authoring default. Apply independent legal and player limits as additional bounds.

typescript
import { permittedStakes } from './slot-session';

// approvedMin/approvedMax include effective configuration and player limits.
const stakes = permittedStakes(config, gameSettings, {
  min: approvedMin,
  max: approvedMax,
});
if (stakes.length === 0) {
  // Disable paid play. Show a configuration error. Do not invent a stake.
}

stakes is optional in the SDK. Some games use a numeric stake input. Validate that input against explicit effective bounds. Agree its increments and rounding with the operator. An absent ladder is not permission to accept every amount.

Default and restored stakes

Apply defaultStakeIndex to the final displayed ladder. Clamp an out-of-range index to an available entry. Do not use an index from the unfiltered ladder.

When forceDefaultStake is true, ignore the saved preference at a new session. Otherwise restore a saved value only if it remains legal.

An open round has its own stake. Restore that value before a continuation. Do not replace it with today's default or a newly filtered value. Lock the stake selector during the round. Resolve changed limits through recovery or operator support.

Apply the same validation to pointer controls, keyboard controls, autoplay, and Operator Interface events. A wrapper request cannot bypass the stake validator.

Feature purchases

Show the base stake and the complete cost before confirmation:

text
base stake = 100
feature.price = 80
debit = 100 × 80 = 8000

Send stake: 100 and the returned feature id. Do not send stake: 8000. The engine calculates the debit.

For slots, require packageBuyEnabled and a returned buy option. Check the complete cost against balance and approved purchase limits. Recheck after confirmation if settings or the stake changed.

Current engine handlers compare maxPackageStake against the requested base stake. No handler compares it against the complete purchase cost. Apply the complete-cost check in your frontend. Include this difference in operator acceptance tests.

Other verticals use featureToBuy to select an ordinary table, often at price 1. These selections are not necessarily slot bonus purchases. Agree their permission mapping for that vertical. See game guides.

Base stake on a bought round

For a buy, the RGS can report the full debit in both gameRoundInfo.stake and gameRoundInfo.baseStake. Prefer result.engineData.baseStake for win conversion, including after reload.

typescript
import { roundBaseStake } from './slot-session';

const base = roundBaseStake(snapshot);
const displayedWin = Math.floor(snapshot.result!.totalWin * base);

Example: a base stake of 100, purchase price of 80, and totalWin: 12 yields 1200. It does not yield 96000.

The helper rejects a bought round without its recorded base stake. Resolve an older round from authoritative history. Do not divide by a current feature price that might have changed.

Balance, cumulative wins, and limits

Replace the displayed balance with each authoritative balance reply. Do not add totalWin to it. A reply may already include the credit.

Never sum successive totalWin values. They describe the accumulated result, not a sequence of new payments. Consolidated scenarios can report zero until the final step.

The engine floors a converted win to integer units. Use server amounts for settlement and account displays. Use scenario amounts only for animation breakdowns.

maxExposure limits a round's payout. The engine can cap totalWin and end the round early. Honor returned state even when feature counters still show unused spins. Do not add the discarded spins or an uncapped scenario sum back into the win.

calculatedMaxExposure reports the reachable amount when the engine can calculate it. maxPayoutCap is not currently supplied by loadConfig.

Net position

A session net position measures play, not deposits or withdrawals. Do not calculate it from a balance difference.

The session carries no net-position counters. tokenData is V2_GameToken, and it holds session identity only: operatorId, playerId, gameId, mode, currency, currentToken, gameRound, walletMode, language, currencyMultiplier, device, commonDraw. The totalBetAmount and totalWinAmount fields in the Operator API are per round, not per session.

Retain a session ledger of confirmed round debits and credits. Key entries by round and transaction identity. Exclude wallet deposits and duplicate replay animations. Preserve the agreed session boundary through refresh and reload.

Show unknown totals as unavailable while reconciling. Do not silently reset a required net position to zero. Agree how freeplays, discounts, pending winnings, and resumed rounds enter the session ledger.