Skip to content

Endpoints

The hizi RGS platform provides all endpoints. The initial login() call returns the backendURL and token. The SDK sends requests as JSON POST bodies to the backendURL.

login

Exchange the short-lived launch token for a session token and the URLs for all later calls. The game's launch URL provides the launch token. The response also carries the operator's platform settings (gameSettings). Your frontend must follow these settings, such as stake limits, enabled features, UI behaviour, and regulatory flags.

Request:

typescript
await login({ loginURL, launchToken });

Response: IConnectReply

typescript
{
  token: string;                       // Session token for subsequent API calls
  backendURL: string;                  // URL for game API calls
  refreshURL: string;                  // URL for refreshing the session
  logoutURL: string;                   // Logout URL
  webSocketURL?: string;               // WebSocket URL (optional)
  balance?: IBalanceReply;             // Player balance
  gameSettings?: IGameSettings;        // Operator platform settings - read this!
  tokenData?: ITokenData;              // Token metadata (playerId, currency, mode, …)
  freePlaysAvailable?: IFreePlayInfo[]; // Available free plays
}

Read gameSettings before showing the game

gameSettings values differ by operator and by jurisdiction. These values must control your UI. Your frontend must clamp and validate stakes. Your frontend must also respect every enabled and disabled flag. The engine does not enforce these settings again for you.

Typical fields to apply:

  • Use minStake, maxStake, and maxPackageStake to clamp the stake selector and buy-feature prices.
  • Use customStakes, defaultStakeIndex, and forceDefaultStake to override the game's own stake list.
  • Use maxExposure to cap the maximum win that you show or allow.
  • Use autoplayEnabled, autoplayLossLimitRequired, and autoplayShowTotalStake to control the autoplay UI.
  • Use gambleEnabled, turboEnabled, stopEnabled, partialCollectEnabled, and packageBuyEnabled to enable or disable feature buttons.
  • Use displayRTP, displayXRTP, showExactRTP, displayWinOdds, and displayJackpotOdds to control the disclosure of RTP and odds.
  • Use these fields to control presentation: forceOrientation, disableFullScreenMobile, hideCompanyLogo, displayClock, abbreviateAmounts, displayNetPosition, hideDemoBalance, and displaySessionTimer.
  • Use historyURL, homeURL, topupURL, lossLimitURL, homeEnabled, and redirectTarget for external navigation.
  • If reportAnimationEnd is true, call reportAnimationEnd after every win animation.
  • Use operatorHandlesErrors, translateErrors, preventRedirect, and refreshDisabled to handle errors and sessions.

See IGameSettings for the full field list. Operators may also supply extra fields beyond the typed ones. The index signature [key: string]: unknown exposes these extra fields.

Stake limits precedence

Always intersect the game's own stake list (loadConfigconfig.stakes) with gameSettings.minStake and gameSettings.maxStake. Use gameSettings.customStakes when the operator provides it. The operator's limits override the game's defaults.


loadConfig

Load the game configuration including available stakes, RTP, and buy-features.

Request:

typescript
await loadConfig({ backendURL, token });

Under the hood, this sends:

json
{
  "op": "loadConfig",
  "token": "<session-token>"
}

Response: ILoadConfigReply

typescript
{
  config: {
    gameCode: string;
    gameType?: string;             // Set for rules-engine games (e.g. 'mines', 'crash', 'keno', 'roulette'). Absent for fixed-odds slot/plinko games.
    stakes?: number[];             // Available stake amounts (optional)
    rtp: number;                   // Return to player percentage
    maxPayoutCap?: number;         // Maximum payout cap
    maxWagerableWin?: number;       // Maximum win amount eligible for wagering
    minWagerableWin?: number;      // Minimum win amount eligible for wagering
    version: string;               // Engine version
    buyFeatures?: IBuyFeatureOption[]; // Available buy-features (with `id` added)
    wagerFeatures?: string[];            // Relative wager features (e.g. ["color-red", "color-black", ...])
    wagerStakeFeatures?: string[];       // Absolute cashout wager features (e.g. mines/frogger steps)
    progressionCounters?: IProgressionCounterConfig[]; // Progression counter configs
    progressionCounterValues?: Record<string, number>; // Current counter values (0.0–1.0)
    [key: string]: unknown;            // Additional fields from loadConfig.json
  };
  tokenData: ITokenData;              // Updated token data
  balance?: IBalanceReply;             // Player balance
  gameResult?: IGameResult;            // Last game result (if resuming)
  gameRoundInfo?: IGameRoundInfo;      // Game round info (if resuming)
  freePlaysAvailable?: IFreePlayInfo[]; // Available free plays
  previousResults?: IGameResult[];     // Previous game results
  amountToCollect?: number;            // Uncollected amount
}

Key fields:

FieldDescription
config.gameTypeSet for rules-engine games (for example 'mines', 'crash', 'keno', 'roulette'). Absent for fixed-odds slot or Plinko games. Use this field to select game-specific UI.
config.stakesArray of available stake amounts, in minor currency units. Optional. Some games use custom stakes set by the operator.
config.rtpReturn to player percentage (for example, 95 for 95%)
config.buyFeaturesAvailable buy-feature options. See buy-features
config.wagerFeaturesAvailable wager feature names (absent if the game has no wager features). See gamble-features
config.progressionCountersProgression counter configuration. See Progression Counters
config.progressionCounterValuesCurrent counter values per player (0.0–1.0 range)
gameResultThe last game result if the player has an incomplete round to resume

placeBet

Place a bet to receive a game result. You can also continue an in-progress round with this endpoint.

Request:

typescript
// New spin
await placeBet({ backendURL, token, stake, config });

// Continue multi-step round
await placeBet({ backendURL, token, config });

// Buy feature
await placeBet({
  backendURL,
  token,
  stake,
  featureToBuy: featureId,
  config,
});

config is the object that loadConfig() returns (configResponse.result.config). Passing config enables automatic decompression of the scenario field. Without config, the engine returns scenario in its compressed (minified) form.

Under the hood:

json
{
  "op": "placeBet",
  "token": "<session-token>",
  "stake": 100,
  "featureToBuy": "freespin"
}

Options: IPlaceBetOptions

FieldTypeRequiredDescription
backendURLstringYesBackend URL from login response
tokenstringYesSession token
stakenumberNoStake amount. Required for the first call of a gameround.
useTicketbooleanNoUse a freeplay ticket
useTicketFeatureTypestringNoFeature type of the ticket
featureToBuystringNoFeature to buy (for example, 'freespin'). The engine derives the price from the stake.
configILoadConfigConfigNoConfig from loadConfig(). Required to decompress the scenario field.
playerChoiceIndexnumberNoIndex of the selected option when engineData.playerChoice is set
additionalDataRecord<string, unknown>NoAdditional game-specific parameters

Response: IPlaceBetReply

typescript
{
  result: IGameResult;            // The game result
  tokenData: ITokenData;          // Updated token data
  balance?: IBalanceReply;        // Updated balance
  gameRoundInfo?: IGameRoundInfo; // Game round status
  amountToCollect?: number;       // Uncollected amount
}

The key payload is result, an IGameResult:

typescript
{
  // Your scenario data (from hizi engine generator)
  scenario: Record<string, unknown>;

  // Engine state
  engineData: {
    // Fixed-odds (entries-DB) games only - omitted by rules-engine games
    // such as blackjack and crash.
    entryIndex?: number;
    scenarioInfo?: IScenarioInfo;
    spinInfo?: ISpinInfo[];
    playerChoice?: TPlayerChoiceAward[];
    currentFeature?: string;
    nextFeature?: string;
    progressionCounters?: Record<string, number>;
    canCollect?: boolean;
    inProgress: boolean;
    buyFeatureId?: string; // Id of the feature this round was opened by buying, if any
  };

  // Cumulative win (multiplier of stake)
  totalWin: number;
}

TIP

If the round opened with featureToBuy, every reply for that round echoes back which feature it was. This includes every continuation placeBet call and the closing collect call. The field is result.engineData.buyFeatureId. Use this field to attribute the round's total win to the bought feature. You do not need to track the feature on the client side. The field is absent (undefined) for a round that did not open by buying a feature. Older engine versions also duplicated this field at the reply root as buyFeatureId. That copy no longer exists. Read the field from engineData instead.

Decision logic after you receive a response:

ConditionAction
engineData.playerChoice is setPresent options to the player. Then call placeBet with playerChoiceIndex: N.
engineData.inProgress === trueCall placeBet({ backendURL, token }) to continue
engineData.inProgress === false and totalWin > 0If the game has wager features, call collect() to cash out. Otherwise, the round ends automatically. You do not need to take action.
engineData.inProgress === false and totalWin === 0The round is complete. Enable the next spin.

TIP

Games without wager features always end the round automatically when the game completes. A game has no wager features when both config.wagerFeatures and config.wagerStakeFeatures are absent. The engine credits winnings automatically. You do not need to call collect().


collect

Collect winnings after a completed round. This endpoint is available only for games with wager features. A game has wager features when config.wagerFeatures or config.wagerStakeFeatures is present. Games without either wager feature type end the round automatically. The engine credits winnings automatically for these games.

Request:

typescript
// Collect full amount
await collect({ backendURL, token });

// Collect partial amount
await collect({ backendURL, token, amount });

Under the hood:

json
{
  "op": "collect",
  "token": "<session-token>",
  "collectAmount": 5000
}

Options: ICollectOptions

FieldTypeRequiredDescription
backendURLstringYesBackend URL from login response
tokenstringYesSession token
amountnumberNoAmount to collect. If you omit this field, the engine collects the full available amount
additionalDataRecord<string, unknown>NoAdditional game-specific parameters (for example, the crash betHash from crashCollectData())

Response: ICollectReply

typescript
{
  amountCredited: number;  // Amount credited to balance
  amountToCollect: number; // Amount that was requested
  balance?: IBalanceReply; // Updated balance
  tokenData: ITokenData;   // Updated token data
  result?: IGameResult;    // Final game result - closed engineData (and buyFeatureId, if bought); see placeBet
}

WARNING

Only call collect when:

  • The game has wager features (config.wagerFeatures or config.wagerStakeFeatures is present)
  • engineData.canCollect === true
  • totalWin > 0 (there are winnings to collect)

If you call collect on a game without wager features, the engine returns an error.


pfVerify

Replay any past round from its revealed seeds. If the round had player actions, replay those too. pfVerify reruns the exact game logic that the live round used. It returns the full result and the per-call RNG audit. You can compare this audit against what you recorded at round time.

This endpoint works only for provably-fair rounds. A provably-fair round runs with config.rng === 'pf'. The endpoint never touches the wallet, progression counters, or operator caps. It is pure compute.

Request:

typescript
import { pfVerify } from '@hizi.io/engine-sdk';

const reply = await pfVerify({
  backendURL,
  token,                              // current session token (auth + gameId routing)
  serverSeed: pf.revealedServerSeed,
  clientSeed: pf.clientSeed,
  stake: 100,                         // the stake the round opened with
  featureToBuy: 'freespin',           // if the round opened on a buy feature
  initialData: { /* … */ },           // blackjack side bets
  bets: [ /* … */ ],                  // roulette / crash opening bets
  playerNumbers: [ /* … */ ],         // keno picks
  actions: [
    { playerChoiceIndex: 0 },         // fixed-odds wager choice
    { pickPosition: 12 },             // mines pick
    { action: { kind: 'hit' } },      // blackjack action (TRulesAction shape)
  ],
});

Under the hood, the SDK POSTs to backendURL:

json
{ "op": "pfVerify", "token": "<session-token>", "serverSeed": "…", "clientSeed": "…", "…": "…" }

Options: IPfVerifyOptions

FieldTypeRequiredDescription
backendURLstringYesBackend URL from the login response.
tokenstringYesSession token. The engine uses it only to resolve the gameId to the game config. The endpoint makes no wallet calls.
serverSeedstringYesThe revealed server seed from the round's pf block.
clientSeedstringYesThe client seed for that round.
startNoncenumberNoDefaults to 0. Set it if your round opened mid-stream against an existing provably-fair session.
stakenumberNoRequired by games that need the stake to settle. Examples: blackjack settlement math, and Frogger or other fixed-odds wager games.
featureToBuystringNoMirror the round's opening featureToBuy value. Examples: the Mines mine count, or a Slot bonus buy.
initialDataRecord<string, unknown>NoMirror the round's opening payload. Currently this is blackjack's { sideBets }.
betsunknown[]NoRoulette's IRouletteBet[] or Crash's IBet[]. These are the round's opening bets.
playerNumbersnumber[]NoKeno: the player numbers, if the round was opened with explicit picks.
actionsIPfVerifyAction[]NoContinuation actions, in order. The shape depends on the game. See the game's Provably Fair section under Games.

Response: IPfVerifyReply

typescript
{
  rngData: IRngDataEntry[];   // per-call audit, same shape as the live `pf.rngData`
  steps: IGameResult[];       // per-step game outcomes, terminal step last (length 1 for one-shots)
}

Two fields, two checks:

  1. Audit replay: compare rngData element by element against the round's saved pf.rngData. Rows of type 'int' must match exactly. Rows of type 'double' must match within a float tolerance. A swapped server seed produces different draws. A passing comparison proves the revealed seed is the seed that the round committed to.
  2. Result replay: compare each steps[i].scenario and steps[i].totalWin value to what the live round returned at the matching step. For one-shot games, this is just steps[0]. For multi-step rounds (blackjack, Mines, Hi-Lo), this is the full per-step chain.

If both checks match, only (serverSeed, clientSeed, actions) determined the round. The engine could not have rigged the outcome.

engineData is preserved

Each step is a full IGameResult. steps[i].engineData carries the engine's per-step flow-control state: playerChoice (fixed-odds wager-feature offerings), inProgress, and nextFeature. Use this data to verify the round's flow, not just the final outcome. For example, confirm that a fixed-odds round showed the expected wager choices.

Defence-in-depth commit check

For an explicit commitment check on top of the audit replay, compute SHA-256(serverSeed) on the client. Compare the result to the serverSeedHash you saved before the round opened. This takes one crypto.subtle.digest call. The engine does not need to return this value.

Scope

pfVerify skips the operator-side post-processing that the live placeBet call runs. This includes progression counters, gameSettings.maxExposure caps, and supplemental stake debits. You cannot derive these from the provably-fair commitment. Verification covers only the RNG draws and the game logic that uses them.

Crash

Crash player-cashout timing depends on the wall clock, not on the seed. pfVerify for Crash returns only the committed scenario.maxMultiplier. This is the entire seed-derived surface. The operator audits bet settlements.

See Provably Fair for the underlying HMAC-SHA512 protocol. That page also explains how the protocol derives the seeds from (serverSeed, clientSeed, nonce).


refresh

Refresh an expired session token. Call this when API requests return SESSIONINVALID or NOTLOGGEDON errors.

Request:

typescript
await refresh(refreshURL);

The initial login() response provides the refreshURL (result.refreshURL).

Response: IConnectReply

typescript
{
  token: string;                     // New session token
  backendURL: string;                // Backend URL (may change)
  refreshURL: string;                // New refresh URL
  logoutURL: string;                 // Logout URL
  webSocketURL?: string;             // WebSocket URL
  balance?: IBalanceReply;           // Player balance
  gameSettings?: IGameSettings;      // Platform settings
  tokenData?: ITokenData;            // Token metadata
  freePlaysAvailable?: IFreePlayInfo[]; // Available free plays
}

TIP

After a successful refresh, update your stored token, backendURL, and refreshURL with the new values from the response.


reportAnimationEnd

Notify the backend that the game animation has finished. Use this endpoint when the operator requires animation-end reporting (see gameSettings.reportAnimationEnd).

Request:

typescript
await reportAnimationEnd({ backendURL, token });

updateBalance

Request an updated balance from the backend.

Request:

typescript
await updateBalance({ backendURL, token });