Appearance
Place a bet, starting the gameround or adding to the open one
POST
/startGameOrAddBet
Optional. Places a bet. It starts a new gameround on the first bet
and appends a further debit to the open gameround on each later bet.
Use this call only for a game that expects more than one debit.
Use POST /startGameRound for every other game. /startGameRound is
the safer call: it starts exactly one gameround and takes exactly one
debit, so it rejects a duplicate bet that this call accepts. Choose
/startGameOrAddBet only when the game design puts two or more bets in
one gameround.
The request body is identical to POST /startGameRound
(V2_StartGameRoundRequestBody), and so is the reply.
A player has only one open gameround at a time. startGameRound
always marks its debit as the first debit of a new round, so a
second startGameRound on an open round fails with
GAMEROUNDALREADYSTARTED (12). That is correct behaviour; send the
second bet here instead.
How the call chooses between "start" and "add bet". It compares
externalGameProviderRoundId in the request with the round on the
session token (tokenData.gameRound):
- absent, or different from the round on the token: it starts a new
gameround and behaves exactly likestartGameRound; - equal, and
debitInformation.externalGameProviderTransactionId
differs from the first bet of that round: it adds a bet to the open
round; - equal, and
debitInformation.externalGameProviderTransactionId
equals the first bet of that round: it repeats the first bet, so a
lost first bet is safe to send again.
Sending more than one bet in one round:
- send the first bet here with
externalGameProviderRoundIdset to
your own round id (hizi.io then uses that value as the gameround
hash verbatim); - send each later bet here with the same
externalGameProviderRoundId; - give every bet its own
debitInformation.externalGameProviderTransactionId; - keep both identifiers to 32 characters or fewer;
- send
rngResulton every bet, carrying the keysrngCallId,
resultandwinAmount(the values may benulland0); - add one win per bet with
POST /addWin, each with its own
externalGameProviderTransactionIdandcollect: trueto pay the
player; - close the round with
POST /endGameRound.
Limits.
endGameandcreditInformationare ignored on a bet that is added
to an open round. Only the call that starts the round reads them.
Close the round withPOST /endGameRound.- A repeated
debitInformation.externalGameProviderTransactionIdon a
later bet fails withTRANSACTIONALREADYEXISTS(37). It is not a
silent success. - A bet cannot join a round that was started without
externalGameProviderRoundId: the comparison above can never match.
Set the field on the first bet even when you expect only one bet.
Retry semantics: idempotent on
debitInformation.externalGameProviderTransactionId while the round is
open. On a lost response, query with POST /getGameRoundInfo rather
than blindly repeating the debit.
Authorizations
V2AuthId
Game provider ID assigned by hizi.io (Hinterzimmer). Identifies which
shared secret the signature must be verified against. Mandatory on
every game engine / RGS call.
Type
API Key (header: X-H-AUTH-ID)
V2Signature
HMAC signature of the request. OpenAPI cannot express a computed
signature, so the scheme is modelled as an apiKey header; the value
is derived per request as follows.
You need a shared secret, which you can retrieve by logging in to the
hizi.io backoffice with your credentials. The signature is a
base64-encoded SHA-256 HMAC digest of a defined set of request
parameters, joined with a hash character (#). This allows the secret
to be shared without ever being sent in the request. A timestamp
(X-H-TIMESTAMP) must also be supplied as a request header and is part
of the signed data.
Outbound (you → hizi.io RGS) — the fields signed are the
serialised JSON body and the timestamp:
X-H-AUTH-SIG = base64(
HMAC_SHA256( secret, [ JSON.stringify(body), X-H-TIMESTAMP ].join('#') )
)
See the Signing appendix for a complete
reference implementation.
Inbound (hizi.io RGS → your backendQueue) — same primitive, but
the RGS signs a fixed, per-endpoint ordered list of scalar fields
and the body is not hashed. The secret is used both as the HMAC key
and as the first element of the signed string:
X-H-AUTH-SIG = base64( HMAC_SHA256( secret, fields.join('#') ) )
| endpoint | fields (in order) |
|---|---|
GET /getGameConfiguration |
[ secret, X-H-AUTH-ID, X-H-TIMESTAMP, currency ] |
POST /getGameResult |
[ secret, X-H-AUTH-ID, X-H-TIMESTAMP, gameRound ] |
A wrong signature is reported as HTTP 401 / error code 1001
(SIGNATUREWRONG) and must not be retried.
The header family is shared with the Operator API, which documents the
same base64/SHA-256-HMAC/#-joined construction; the set of signed
fields differs per API and per direction, so do not assume a signer
written for one is reusable for the other without checking the field
list.
Type
API Key (header: X-H-AUTH-SIG)
V2Timestamp
ISO 8601 timestamp of the request (e.g. 2023-01-26T11:28:21.429Z).
Mandatory, and included in the signed data of X-H-AUTH-SIG.
Type
API Key (header: X-H-TIMESTAMP)
Parameters
Header Parameters
X-Request-Id*
Unique ID identifying the call in the logs. Documented as a mandatory
request header for all game engine / RGS calls.
Note: the reference implementation in the
Signing appendix additionally sets
X-Response-Id (a fresh UUID) and, when relaying a request,
X-Forwarded-Response-Id.
Type
Requiredstring
Example
"8c00b93dd861405cbeb7c14fded1e72a"Request Body
application/json
JSON "token": "83020869-abc0-4123-a95e-ee4f5e8e8343", "externalGameProviderRoundId": "round-0001", "rngResult": { "rngCallId": "5cd23259ea4c49e7b955e79321da4365", "result": "", "winAmount": 0 }, "debitInformation": { "debitAmount": 100, "currency": "EUR", "externalGameProviderTransactionId": "bet-0001" }, "endGame": false
{
}
Responses
Bet accepted. gameRoundInfo.hash is the round the bet belongs to,
and equals externalGameProviderRoundId when you supplied one.
gameRoundInfo.status is open, or closed when this call
started the round with endGame: true. gameRoundInfo.stake is
the total staked in the round so far, so it grows with each added
bet.
application/json
JSON "tokenData": { "operatorId": "string", "playerId": "string", "gameId": "string", "mode": "string", "currency": "EUR", "currentToken": "string", "gameRound": "ff85e29cb4414c89a89829c8411dacc2", "walletMode": "string", "language": "DE", "currencyMultiplier": 1, "device": "string", "commonDraw": "string" }, "balance": { "totalBalance": 0, "mode": "string", "currency": "EUR", "balances": [ { "type": "real", "currency": "EUR", "amount": 0 } ], "discountInfo": { "text": "string", "currency": "EUR", "discounts": [ { "stake": 0, "absoluteDiscountAmount": 0, "spinsRemaining": 0 } ], "campaignId": "string", "validFrom": "string", "validTo": "string" }, "tickets": [ { "count": 0, "stake": 0, "currency": "EUR", "price": 0, "feature": "string", "serial": "string" } ], "ticketInfo": { "used": 0, "granted": 0, "won": 0, "isLast": true, "promotions": { "protocolVersion": 0, "data": "string" }, "serial": "string" } }, "gameRoundInfo": { "hash": "ff85e29cb4414c89a89829c8411dacc2", "status": "open", "stake": 0, "baseStake": 0, "mode": "string", "currency": "EUR", "game": "string", "currencyMultiplier": 0, "commonRoundHash": "ff85e29cb4414c89a89829c8411dacc2" }, "commonGameRoundInfo": { "additionalProperties": "string" }, "gameState": [ { "hash": "ff85e29cb4414c89a89829c8411dacc2", "type": "debit", "processedOn": "string", "result": { "winAmount": 0, "info": { "additionalProperties": "string" } }, "amountWagered": 0, "collected": 0, "reason": "collect 0.37 EUR" } ], "amountToCollect": 0, "amountCredited": 0, "freePlayInfo": { "used": 0, "granted": 0, "won": 0, "isLast": true, "promotions": { "protocolVersion": 0, "data": "string" }, "serial": "string" }, "freePlaysAvailable": [ { "currency": "EUR", "stake": 0, "count": 0, "feature": "string", "serial": "string" } ], "passThroughData": { "additionalProperties": "string" }, "promoWinInfo": { "referenceId": "string" }
{
}