Skip to content

Endpoints ​

The hizi RGS platform provides all endpoints. The initial login() call returns the backendURL and token. The SDK sends game operations as JSON POST bodies to backendURL. Login and refresh use GET on their supplied URLs. Do not append operation names to 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, gameId, language, currency, mode, currencyMultiplier, gameRound, …)
  freePlaysAvailable?: IFreePlayInfo[]; // Available free plays
  featuresAvailable?: { game: string; type: string; rtp: number; value: number; description?: string }[];
  operatorProtocol?: number;          // Operator protocol version in use (informational)
}

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 validates financial requests, but it does not implement frontend controls or disclosures. Apply all frontend requirements explicitly.

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

Operator limits replace the corresponding game defaults. A nonempty customStakes list replaces the default ladder. The current engine custom-list path skips its separate min/max checks. Filter the selected ladder against effective player and jurisdiction limits yourself. See stakes and money.

SDK login and refresh copy a fixed list of eleven top-level keys and discard the rest of the raw reply. tokenData is one of them, so playerId, operatorId, gameId, language, currency, currencyMultiplier, mode and any open gameRound all reach your frontend. Every other SDK operation returns the raw reply unchanged, so loadConfig gives back gameRoundInfo and amountToCollect straight after. Only gameVariables.rcElapsed and the singular freePlayInfo are lost for good. Do not replace login to recover them. See what login() does not return.


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;             // Game vertical; optional in older configurations
    stakes?: number[];             // Available stake amounts (optional)
    minStake?: number;             // Effective minimum stake
    maxStake?: number;             // Effective maximum stake
    calculatedMaxExposure?: number; // Effective monetary exposure limit
    ladderMultipliers?: number[];  // Built-in ladder gamble configuration
    ladderLives?: number;
    rtp: number;                   // Return to player percentage
    maxPayoutCap?: number;         // Maximum payout cap (the engine does not set this on loadConfig)
    maxPayout?: number;            // Highest payout one round can accumulate, as a multiplier of stake
    maxPayoutOdds?: number;        // "1 in N" denominator for maxPayout (currently repeats maxWinOdds)
    maxWin?: number;               // Highest win one spin can pay, as a multiplier of stake
    maxWinOdds?: number;           // "1 in N" denominator for maxWin in ordinary play
    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. ["card_red", "card_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.gameTypeThe current game vertical, including fixed-odds types. Older configs can omit it. Validate it against your frontend.
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.maxPayoutThe four certified figures a game states are maxPayout, maxPayoutOdds, maxWin and maxWinOdds. Print them on the rules screen. A figure the game does not have is absent, never 0. See ILoadConfigConfig
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. Passing config makes the SDK expand a minified scenario before it resolves. Without config, scenario stays minified. The option does nothing for a game that does not minify scenarios.

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: {
    // entryIndex, scenarioInfo and spinInfo come from the fixed-odds (entries-DB)
    // pipeline. Rules-engine games such as blackjack and crash omit those three.
    // Every other field below, including inProgress and canCollect, applies to all games.
    entryIndex?: number;
    scenarioInfo?: IScenarioInfo;
    spinInfo?: ISpinInfo[];
    playerChoice?: TPlayerChoiceAward[];
    currentFeature?: string;
    nextFeature?: string;
    progressionCounters?: Record<string, number>;
    canCollect?: boolean;
    inProgress: boolean;
    buyFeatureId?: string; // Opening purchase identifier
    baseStake?: number;              // Base stake for the round, EXCLUDING buy-feature cost
    bankedWin?: number;   // Protected win multiplier, still unpaid
    ladderState?: { baseWin: number; currentRungIndex: number; lives: number; previousRungIndex?: number };
    version?: string;
  };

  // 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 SDK path is response.result.result.engineData.buyFeatureId after checking response.success. 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 presentation and required timing:

StateAction
Closed round with consistent terminal engine flagsEnable a new player-requested round.
engineData.canCollect === trueOffer collect. Offer only permitted choices or explicit continuation.
Nonempty engineData.playerChoiceWait for a player choice. Preserve its original index.
engineData.inProgress === true, without either condition aboveFollow the vertical's continuation contract.
Open round without a legal action, or contradictory stateRecover before another request.

The checked slot controller implements this order. A positive totalWin does not authorize collect. An inProgress flag does not authorize an automatic gamble.

Games without a collect phase normally settle automatically. Render their final balance and result. Do not collect a second time after settlement.


collect ​

Collect when the vertical offers cashout. Fixed-odds games signal this with engineData.canCollect. Crash uses its live bet hashes. Ordinary slot rounds without a collect phase settle automatically.

A partial collect during an open gamble banks a protected amount. It keeps the round open and does not immediately credit the wallet. See gamble and banking.

Request:

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

// Bank part of an open gamble win, when permitted
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; // Actual credit, absent when only banking
  amountToCollect: number; // Amount that was requested
  balance?: IBalanceReply; // Updated balance
  tokenData: ITokenData;   // Updated token data
  result?: IGameResult;    // Updated state; can remain open after banking
  gameRoundInfo?: IGameRoundInfo;
}

collect has no config option. If its reply contains a compressed result, call decodeScenario(reply.result.result, config) after checking success.

Use the returned round status and engine flags to determine settlement. If they are missing, reload state. Do not treat amountToCollect on this reply as a guaranteed remaining balance. Its SDK contract describes the requested amount. Reload authoritative outstanding amounts before another partial collect.

Omit amount for full collection. Do not subtract a previously banked amount. A successful response alone does not prove that the round closed.


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 ICrashBet[]. 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' carry the raw HMAC float and must match exactly. Use a deep-equal over the array. 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 });