Skip to main content

Reacting to Events

Kalamba SDK emits the following events. Each section states how the Game Client MUST or MAY react:

Balance

When received, the Game Client MUST update in-game balance if separate balance indicator exists in game.

type BalancePayload = { balance: number }

sdk.on('balance', payload => {
game.setBalance(payload.balance)
})

When received, the Game Client MUST update legal bets available in game. The payload maps each legal base bet value to the list of legal bet multipliers for that base.

type LegalBetsPayload = Record<number, number[]>

sdk.on('legalBets', payload => {
game.setLegalBets(payload)
})

Bet

When received, the Game Client MUST update in-game bet if separate bet indicator exists in game.

type BetPayload = { base: number; multiplier: number }

sdk.on('bet', payload => {
game.setBet(payload)
})

Cashier

Emitted when the casino's cashier was opened. The type field tells why — on the player's demand, or because the balance ran low or became insufficient. The Game Client MAY use this event to adjust its UI while the cashier is shown.

type CashierPayload = { type: 'ON_DEMAND' | 'BALANCE_LOW' | 'BALANCE_INSUFFICIENT' }

sdk.on('cashier', payload => {
game.onCashierOpened(payload.type)
})

Choice

When received, the Game Client MUST resolve a pending choice previously requested with sdk.send('choice', ...). The payload carries the id of the option selected by the player.

type ChoicePayload = { id: string }

sdk.on('choice', payload => {
game.resolveChoice(payload.id)
})

Close

When received, the Game Client MAY use this event to do some last minute housekeeping. The game will be closed imminently, so the Game Client SHOULD use the Beacon API if it plans to make any network requests. This event has no payload.

sdk.on('close', () => {
game.close()
})

Configured

When received, the Game Client MAY read the resolved SdkConfig to adjust available features and UI. The SDK also stores this payload internally and exposes it as sdk.config after the game has been opened.

sdk.on('configured', config => {
game.applyConfig(config.ui.feature)
})

Wrapper Configured

Emitted when the wrapper has processed the configure message. The Game Client normally does not need to listen to this event directly — the promise returned by sdk.configure(...) resolves when it is received. This event has no payload.

sdk.on('wrapperConfigured', () => {
game.onWrapperReady()
})

Error

When received, the Game Client MAY react to an error surfaced by the wrapper. The type field describes how the wrapper resolves the error: CLOSE, RELOAD or CONTINUE.

type SdkError = {
messageCode: string
type: 'CLOSE' | 'RELOAD' | 'CONTINUE'
} & ({ message: string } | { messageKey: string })

sdk.on('error', payload => {
game.onError(payload)
})

Freeze

When received, the Game Client MUST pause the game and prevent further gameplay and interactions with the user interface. The Game Client MUST stop autoplay if it is engaged. The Game Client MAY finish the animations that were already playing when the event was received, but it is RECOMMENDED that all animations are paused as well. This event has no payload.

sdk.on('freeze', () => {
game.freeze()
})

Game Help

When received, the Game Client MUST toggle game help. The payload is OPTIONAL — when present, show indicates whether help should be shown or hidden; when absent, the Game Client SHOULD toggle the current state.

type HelpPayload = { show: boolean } | undefined

sdk.on('help', payload => {
game.toggleHelp(payload?.show)
})

Game Paytable

When received, the Game Client MUST toggle game paytable. The payload is OPTIONAL — when present, show indicates whether the paytable should be shown or hidden; when absent, the Game Client SHOULD toggle the current state.

type PaytablePayload = { show: boolean } | undefined

sdk.on('paytable', payload => {
game.togglePaytable(payload?.show)
})

History

Emitted when the game history was opened. The source field tells where it was opened from. The Game Client MAY use this event to adjust its UI while the history is shown.

type HistoryPayload = { source: 'realityCheck' | 'settings' | 'casino' }

sdk.on('history', payload => {
game.onHistoryOpened(payload.source)
})

Play Ready

Sent after playEnd, once all pending play blockers (e.g. wrapper popups) have resolved, signaling that the Game Client may start a new play. This event has no payload.

sdk.on('playReady', () => {
game.enableSpin()
})

Reality Check

Carries the reality check data reported by the RGS: the session duration and the cumulative bet and win amounts. The wrapper shows its own reality check popup by default; a Game Client that disables it with showRealityCheck: false MUST present the reality check to the player itself (see Wrapper Features).

type RealityCheckPayload = {
duration: number
sumBetAmount: number
sumWinAmount: number
}

sdk.on('realityCheck', payload => {
game.showRealityCheck(payload)
})

Resume

When received, the Game Client MUST resume autoplay if it was previously paused in response to suspend event. When received, the Game Client MAY ignore the event if resuming autoplay is not possible. This event has no payload.

sdk.on('resume', () => {
game.resumeAutoplay()
})

Settings

When received, the Game Client MUST update in-game settings. The payload MUST include only settings that have been changed.

type SettingsPayload = {
fastPlay?: boolean
sounds?: boolean
music?: boolean
}

sdk.on('settings', payload => {
game.updateSettings(payload)
})

Suspend

When received, the Game Client MUST pause autoplay if it is engaged. When received, the Game Client MAY stop autoplay instead if pausing autoplay is not possible. This event has no payload.

sdk.on('suspend', () => {
game.pauseAutoplay()
})

Unfreeze

When received, the Game Client MUST unpause the game and allow further gameplay and interactions with the user interface. The Game Client MUST resume any animations that were paused by the freeze event. This event has no payload.

sdk.on('unfreeze', () => {
game.unfreeze()
})

Free Rounds

See Free Rounds for the full lifecycle. The events below share these payload shapes:

type FreeRound = {
conf: {
base: number
multiplier: number
numAwarded: number
}
data: {
numPlayed: number
win: number
numLeft: number
}
id: string
rejectable: boolean
skippable: boolean
status: 'PENDING' | 'ACTIVE' | 'FINISHED'
type: string
}

type FreeRoundsAction = {
action: 'ACCEPT' | 'DECLINE' | 'SKIP'
id: string
}

freeRounds

Carries a FreeRoundsAction — the action taken on a free rounds offer.

sdk.on('freeRounds', payload => {
game.onFreeRoundsAction(payload.action, payload.id)
})

freeRoundsOffer

Carries a FreeRound describing an offered free rounds campaign.

sdk.on('freeRoundsOffer', freeRound => {
game.onFreeRoundsOffer(freeRound)
})

freeRoundsInfo

Carries a FreeRound with the current state of an active free rounds campaign.

sdk.on('freeRoundsInfo', freeRound => {
game.onFreeRoundsInfo(freeRound)
})

freeRoundsComplete

Carries the final FreeRound state when a free rounds campaign has finished.

sdk.on('freeRoundsComplete', freeRound => {
game.onFreeRoundsComplete(freeRound)
})