Skip to content

Player Engagement Overview

The Player Engagement module (sdk.engagement) is the retention heartbeat of the platform. It is an umbrella over four independent engines that share one runtime truth: the player's wagering feed.

The Four Engines

EngineAccessorResponsibility
Bonus Enginesdk.engagement.bonusBonus templates, claiming, wagering requirements, expiry/forfeit (see Bonus Engine)
Loyalty Enginesdk.engagement.loyaltyVIP tiers, XP, progress, tier maintenance/decay, Loyalty Points, shop (see Loyalty Engine)
Promotions Enginesdk.engagement.promotionsTime-windowed campaigns, computed status, claiming; grants bonuses (see Promotions Engine)
Tournament Enginesdk.engagement.tournamentsCompetitive events, opt-in gating, live leaderboards, prize pools and settlement (see Tournament Engine)

Operator-configured, platform-structured

Operators add, edit, and retire every template, tier, campaign, tournament, and shop item in their backoffice; no SDK update or frontend redeploy required. But the structures these live in are fixed by the platform: every engine returns fully typed objects with named fields (never free-form rule bags), and operators configure values inside those structures. Each engine's page lists its Operator-Configurable Values exhaustively.

Catalog lists are complete and unpaginated; a documented exception to standard pagination: these are fixed, small catalogs (templates, tiers, shop items, campaigns, tournaments), so the entire collection is returned in one call. Each list still has a deterministic sort (documented on its engine page) so ordering is reproducible; player-scoped histories (redemptions) and leaderboards follow the standard pagination rules or their documented exceptions.

The Wagering-Feed Contract

The engines are not independent silos; one wager drives them together. The platform's wagering feed is the single source of truth:

typescript
interface Wager {
  playerId: string;     // who wagered
  amount: number;       // wagered amount, in `currency`
  currency: string;     // the wallet currency the wager came from
  gameId?: string;       // game the wager was placed on, when applicable
  balanceSource: 'REAL' | 'BONUS'; // which balance funded the wager
  timestamp: string;    // ISO-8601
}

Three rules govern how a wager advances the engines:

text
RULE 1: REAL MONEY ONLY
GIVEN any wager
WHEN balanceSource is 'BONUS' (bonus funds)
THEN the wager advances NOTHING; no wagering progress, no XP or points,
     no tournament scores. Only real-money wagers drive the engines.

RULE 2: CURRENCY MATCHED (currency-denominated objects only)
GIVEN a real-money wager in currency C
WHEN the feed advances bonuses and tournaments
THEN only objects denominated in C advance; a EUR wager never feeds
     a USD bonus or tournament score. (Multi-wallet model.)
     The loyalty ladder is a single XP aggregate across currencies; its
     multi-currency accrual rule is defined in the Loyalty Engine documentation.

RULE 3: CONFIGURABLE, DOCUMENTED RATES
GIVEN a real-money wager of amount A in the matching currency
WHEN the feed advances the engines
THEN bonus wagering advances by A on every eligible ACTIVE same-currency bonus
     (game eligibility per the bonus template's game list);
     XP and Loyalty Points advance by A × xpRate and A × pointsRate
     (operator-configurable, default 1 per unit; see the Loyalty Engine
     documentation for multi-currency accrual);
     tournament score advances by A × pointsPerCurrencyWagered for each
     opted-in, ACTIVE, same-currency tournament.

One wager, all engines:

Player wagers $10 REAL on Sweet Bonanza

        ├──► Bonus Engine:      wageredAmount += 10 on eligible ACTIVE same-currency bonuses
        │                        (bonus completes when remainingWager hits 0)
        ├──► Loyalty Engine:    XP += 10 × xpRate, Points += 10 × pointsRate
        │                        (tier progress / maintenance recalc)
        └──► Tournament Engine:  score += 10 × pointsPerCurrencyWagered
                                 for every opted-in ACTIVE same-currency tournament

Engagement events

State changes that matter to the player fire on the platform's shared real-time channel: bonus completed or expired, tier changed, tournament completed, prize settled. The channel's transport, delivery guarantees, ticket authentication, and dedupe rules are defined once in the Real-Time Channel reference; each engine defines only its event envelopes (below) and fire conditions.

text
GIVEN an engine state change (bonus completed/expired, tier changed,
     tournament completed, prize settled)
WHEN the transition executes
THEN a typed engine event with an eventId fires on the shared real-time channel.
EventPayload (all carry eventId)
Bonus completed / expiredBonusCompletedEvent / BonusExpiredEvent; see Bonus Engine
Tier changedTierChangedEvent; see Loyalty Engine
Tournament completed / prize settledTournamentCompletedEvent / PrizeSettledEvent; see Tournament Engine

Sandbox

Sandbox runs against rich built-in default data so every engine's dynamic behavior can be tested end-to-end (see Environments & Sandbox Data). The platform-wide time controls (see Sandbox Controls) mean no transition requires waiting on a clock.

javascript
// Sandbox only: the wagering feed
await sdk.engagement.sandbox.simulateWager(25, 'USD', 'game_sweet_bonanza');
// Optional 4th argument proves the bonus-money exclusion rule:
await sdk.engagement.sandbox.simulateWager(25, 'USD', 'game_sweet_bonanza', 'BONUS');
// ^ advances NOTHING (RULE 1: real money only)

In staging/production, sdk.engagement.sandbox is null; the real backend wagering feed (above) takes over.

Migration from Legacy Modules

sdk.engagement replaces the legacy sdk.promotions and sdk.loyalty modules. The legacy accessors remain functional (mapped onto the engines) but are deprecated, and are scheduled for removal in the next major SDK release; the table below maps the deprecated API accessors:

Legacy (deprecated)New
sdk.loyalty.getConfig()sdk.engagement.loyalty.getTiers()
sdk.loyalty.getStatus()sdk.engagement.loyalty.getStatus()
sdk.loyalty.getShop() / redeemItem()sdk.engagement.loyalty.getShop() / redeemItem()
sdk.promotions.getPromotions()sdk.engagement.promotions.getPromotions()
sdk.promotions.claimPromotion(id)sdk.engagement.promotions.claim(id)
sdk.promotions.getActiveBonuses() / forfeitBonus(id)sdk.engagement.bonus.getActiveBonuses() / forfeitBonus(id)
sdk.promotions.getTournaments() / optInToTournament(id)sdk.engagement.tournaments.getTournaments() / optIn(id)
sdk.promotions.getLeaderboard(id)sdk.engagement.tournaments.getLeaderboard(id)