Skip to content

Freeplays ​

Freeplays (free spins or tickets) are bets that an operator grants to a player. A player can spend a freeplay without a wallet debit. Each freeplay has a fixed stake, and optionally a fixed feature, set when the operator grants the package.

How It Works ​

Operators grant and revoke freeplay packages out-of-band, through the Operator API. The engine sends the currently available packages to your frontend as part of the normal session calls. There is no separate "claim" endpoint. Read freePlaysAvailable and spend a ticket with placeBet.

Reading Available Freeplays ​

freePlaysAvailable (an array of IFreePlayInfo) is included in:

typescript
const response = await login({ loginURL, launchToken });
if (response.success) {
  const freePlays = response.result.freePlaysAvailable ?? [];
}

Not echoed by placeBet

IPlaceBetReply does not carry freePlaysAvailable. See Keeping the List in Sync to update your local copy after you spend a ticket.

Each entry groups tickets that share a stake, a currency, and (optionally) a feature. A player can hold several entries at the same time:

typescript
interface IFreePlayInfo {
  currency: string; // ISO 4217 currency code
  stake: number; // Fixed stake amount for each free play
  count: number; // Number of free plays available
  feature?: string; // Optional feature to enter directly (e.g. "freespin")
}

The RGS wire entry also carries a package serial, unique per operator. The SDK type omits it. Read it from the raw reply when your ticket picker must identify one package of several.

Helpers ​

Two helper functions summarize the array. You do not need to reduce the array yourself:

typescript
import { getFreePlaysRemaining, getFreePlayStake } from '@hizi.io/engine-sdk';

const totalRemaining = getFreePlaysRemaining(freePlays); // sum of `count` across all entries
const firstStake = getFreePlayStake(freePlays); // first entry's `stake`, or undefined if none

TIP

getFreePlayStake only reads the first entry. If a player can hold packages at more than one stake or feature, do not rely on this helper alone. Iterate freePlaysAvailable yourself and build a picker.

Choosing a Freeplay ​

Sometimes more than one package is available, with different stakes, or a stake tied to a specific feature such as "freespin". Present the options so the player can pick which one to spend:

typescript
const options = freePlays.map((fp, i) => ({
  value: i,
  label: fp.feature ? `${fp.stake} · ${fp.feature} (${fp.count} left)` : `${fp.stake} (${fp.count} left)`,
}));

Spending a Freeplay ​

Call placeBet with useTicket: true, the ticket's own stake, and (if set) its feature as useTicketFeatureType:

typescript
const freePlay = freePlays[selectedIndex]; // e.g. { currency: 'EUR', stake: 100, count: 5, feature: 'freespin' }

const response = await placeBet({
  backendURL,
  token: sessionToken,
  stake: freePlay.stake,
  useTicket: true,
  useTicketFeatureType: freePlay.feature,
  config,
});

if (response.success) {
  const gameResult = response.result.result;
  // Handle exactly like any other placeBet result - multi-step rounds,
  // player choices, and wager/collect flows all still apply.
}

Still a normal round

A freeplay spin returns a normal IGameResult. It runs through the full game flow (multi-step rounds, player choices, wager/collect). The only difference is that the engine does not debit the stake from the player's balance.

Keeping the List in Sync ​

The reply type does not guarantee an updated ticket list. Reload with loadConfig before the next ticket. Refresh also supplies the list when session renewal is required.

You can reduce a local count after a confirmed opening response for display. Never reduce it on a timeout or again for a continuation. Reconcile uncertain responses before another ticket request. The operator can grant or revoke tickets while the game is open.

Ticket controls and summary ​

Lock the ticket's stake, currency, and feature. Validate its availability and effective limits before the opening request. Never silently replace an invalid ticket with a paid bet.

Apply the same timing, input, rule, and recovery controls as paid play. A granted feature ticket uses useTicketFeatureType. It does not require a paid featureToBuy purchase. Confirm the applicable jurisdiction policy for promotional tickets separately.

Show the number of remaining tickets and the campaign win summary. Accumulate confirmed round winnings once per round identity. Do not add each cumulative feature result again.

Finish all awarded feature steps before displaying the completed campaign. Reconcile the final ticket list and balance. Require a clear player action before switching to paid play. Send the appropriate Operator Interface freeplay events.

Next Steps ​

  • Game Flow - The full game cycle for a freeplay spin. It is the same cycle as any other bet.
  • Endpoints - placeBet parameter reference, including useTicket / useTicketFeatureType.
  • Types - Full IFreePlayInfo field reference.