Casino API · Overview

Casino API · v1

Casino API

The HZURA Casino API lists the games a customer may show, returns a launch URL for one game, and applies BALANCE, DEBIT, CREDIT, and ROLLBACK on that player's wallet. Customers authenticate with an API key, and casino access must be enabled for that customer.

Overview

These routes do not accept customer_id, a provider player id, provider credentials, or a return URL. Unknown JSON fields are rejected. Launch and wallet bodies are limited to 8 KiB.

Bonuses, jackpots, free spins, and promotions are not part of this API. There is no public transaction-status route.

MethodPathPurpose
GET/api/v1/casino/gamesOne page of visible games.
POST/api/v1/casino/games/{gameId}/launchLaunch URL for one game.
POST/api/v1/casino/walletBalance, debit, credit, or rollback.

Games

  • API key required
  • Not rate limited

Endpoint

GET/api/v1/casino/games

Games this customer may see.

Inactive games are hidden. Inactive or removed providers are hidden. Reviewed providers are visible unless this customer has turned that provider off. New providers stay hidden until this customer turns them on.

An empty data array with total 0 is a successful page. A page past the end returns an empty data array and the real total.

images, supported_devices, client_types, supported_currencies, languages, volatility, features, and themes are the catalog values for that game. Treat unused keys as optional.

Authentication

Customer API key and a calling IP inside that customer's CIDR allow-list. Legacy IP-only access is not enough.

Request

Parameters

FieldTypeInRequiredDescription
providerstringqueryNoExact catalog provider id. A different id, including different case, is invalid_provider. Max 200 characters.
categorystringqueryNoExact catalog category id. A different id, including different case, is invalid_category. Max 200 characters.
searchstringqueryNoCase-insensitive match against the game name or description. Max 100 characters.
pageintegerqueryNoInteger greater than or equal to 1. Default 1.
limitintegerqueryNoInteger from 1 to 100. Default 50.
currencystringqueryNoOne of the customer's allowed currencies. Matching ignores case. Max 16 characters. When omitted, the customer's default currency is the visibility filter. If no default is configured, omitting currency does not filter by currency.
languagestringqueryNoKeeps games that list this language. en-US and en_US match. A two-letter code does not match an ll_RR locale. Max 32 characters.
devicestringqueryNoCase-insensitive match against supported_devices or client_types. Max 64 characters. Not limited to desktop and mobile.

Response

200One page of games.

JSON
{
  "data": [
    {
      "id": "DS-example",
      "name": "Example",
      "provider_id": "provider-1",
      "provider_name": "Provider",
      "category": "CASINO/SLOT",
      "categories": [{ "id": "SLOT", "name": "Slot" }],
      "description": null,
      "images": [],
      "supported_devices": ["desktop", "mobile"],
      "client_types": ["HTML5"],
      "supported_currencies": [{ "id": "EUR", "name": "Euro" }],
      "languages": [{ "id": "en_US", "name": "English" }],
      "demo_support": true,
      "free_round_support": false,
      "rtp": "96.5",
      "volatility": null,
      "features": [],
      "themes": [],
      "release_date": null
    }
  ],
  "pagination": { "page": 1, "limit": 1, "total": 1, "total_pages": 1 }
}

Example request

curl
curl -sS "https://api.hzura.com/api/v1/casino/games?limit=1" \
  -H "Authorization: Bearer YOUR_API_KEY"

Errors

HTTPerrorWhen
400invalid_queryA filter is empty or too long.
400invalid_pagepage is not a positive integer.
400invalid_limitlimit is outside 1–100.
400unsupported_currencyCurrency is not on the customer allow-list.
400invalid_providerProvider id is not in the catalog.
400invalid_categoryCategory id is not in the catalog.
403ip_not_allowedNo customer was admitted.
403casino_access_disabledCasino is off for this customer.
503security_config_unavailableAPI-key policy could not be read.
503casino_catalog_unavailableThe catalog could not be loaded.
503redis_unavailableThe catalog store could not be read, including a timeout.

Launch Game

  • API key required
  • Not rate limited

Endpoint

POST/api/v1/casino/games/{gameId}/launch

Return a launch URL for one visible game.

gameId is data[].id from the catalog. It is 1 to 128 characters, must start with an ASCII letter or digit, and may then contain ASCII letters, digits, ., _, or -.

The response is only url. It does not include tokens or the upstream body. The return URL is server configuration. Sending return_url or returnUrl is invalid_launch.

Authentication

Customer API key and a calling IP inside that customer's CIDR allow-list. Legacy IP-only access is not enough.

Request

Headers

FieldTypeRequiredDescription
Content-Type—Yesapplication/json. A body the parser rejects, including a non-JSON content type, is 400 invalid_launch.
Authorization—YesBearer customer API key, or X-Api-Key.

Parameters

FieldTypeInRequiredDescription
gameIdstringpathYesCatalog game id.

Body

FieldTypeRequiredDescription
player_idstringYesThe customer's own player id. 1–64 characters. Starts with a letter or digit, then letters, digits, ., _, or -. The first accepted launch stores it.
currencystringNoOptional. Three letters. Must match the currency already stored for this player, or the customer's default currency on the first launch. Comparison ignores case.
languagestringNoOptional catalog filter, max 16 characters. It does not select the language sent on launch. See Language below.
devicestringNoOptional. desktop or mobile, any ASCII case. Sent as lowercase. It is not saved on the player.
modestringNoOptional. real or demo, any ASCII case. Defaults to real. demo requires demo_support on the game.

Response

200Launch URL.

JSON
{
  "url": "https://games.example/launch/session"
}

Example request

curl
curl -sS -X POST "https://api.hzura.com/api/v1/casino/games/DS-example/launch" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"player_id":"player-1","currency":"EUR","device":"desktop","mode":"real"}'

Errors

HTTPerrorWhen
400invalid_launchBody, game id, or unknown field is not usable.
400unsupported_currencyCurrency does not match the established player or customer currency.
400player_not_configuredCountry, currency, or launch locale cannot be resolved. A new player is not created.
403ip_not_allowedNo customer was admitted.
403casino_access_disabledCasino is off for this customer.
403game_not_availableThe game is not launchable for this request, including demo without demo_support.
404game_not_foundThe game id is not in the catalog.
413payload_too_largeBody is over 8 KiB.
502launch_authentication_failedProvider authentication failed.
502launch_failedProvider rejected the launch or returned no URL.
503security_config_unavailableAPI-key policy could not be read.
503launch_not_configuredLaunch is not configured.
503redis_unavailableThe catalog store could not be read, including a timeout.
503player_store_unavailableThe player store could not be used.
503casino_catalog_unavailableThe catalog could not be loaded.
504launch_unavailableThe provider did not answer. Safe to retry the same launch.

language on the body only filters which game can be launched, the same way the games query does. The locale sent to the provider is the locale stored on the player: the customer's configured locale, or the server locale when the customer has none. en-US and en_US are the same locale and are sent as en_US. A two-letter code such as en is not a launch language. If no ll_RR locale can be resolved, launch is rejected and a new player is not created.

When device is omitted, desktop is used if the game lists desktop or lists no device. Otherwise mobile is used when the game lists it. If neither can be chosen, the game is game_not_available.

Country and currency are taken from the customer's casino configuration on the first launch, then stored on the player. A later launch cannot switch them. currency in the body must match that stored value, ignoring case. The value persisted is uppercase.

Players

There is no separate create-player route. The first launch that passes validation stores player_id for this customer. Later launches and every wallet call reuse that id.

The same player_id at another customer is a different player. One customer cannot read or move another customer's player.

The wallet does not create a player. Call launch before BALANCE, DEBIT, CREDIT, or ROLLBACK. A launch that fails after the player row is stored still leaves that mapping in place. Repeat the launch with the same player_id.

Wallet

One route covers every wallet operation. operation is exactly BALANCE, DEBIT, CREDIT, or ROLLBACK. The balance is the HZURA wallet for that player. BALANCE does not call the game provider and creates the wallet at zero on the first read if the player exists and no wallet row exists yet.

Success responses always include operation, status, currency, and balance. balance is decimal text with trailing zeros removed, so 5.00 is "5" and 12.50 is "12.5". transaction_id is present on transfer results and is the caller's idempotency key, not an internal row id. BALANCE omits it.

status is success for a completed read or transfer. Replaying an original transaction that has since been reversed returns rolled_back.

  • API key required
  • Not rate limited

Endpoint

POST/api/v1/casino/wallet

Read a balance or apply a debit, credit, or rollback.

Authentication

Customer API key and a calling IP inside that customer's CIDR allow-list. Legacy IP-only access is not enough.

Request

Headers

FieldTypeRequiredDescription
Content-Type—Yesapplication/json. A body the parser rejects, including a non-JSON content type, is 400 invalid_wallet.

Body

FieldTypeRequiredDescription
player_idstringYesThe external player id used at launch. 1–64 characters, same character set as launch. The wallet does not create a player.
operationstringYesBALANCE, DEBIT, CREDIT, or ROLLBACK. Any other text is invalid_wallet.
transaction_idstringNoRequired for DEBIT, CREDIT, and ROLLBACK. Idempotency key, unique per customer, including across players. 1–128 characters, same character set as player_id.
amountstring or numberNoRequired for DEBIT, CREDIT, and ROLLBACK. A decimal string is preferred. A JSON number is accepted and then parsed from its text. Greater than zero, at most 8 fractional digits, no sign, no exponent, whole part at most 12 digits, and the text at most 21 characters. A whole part longer than one digit cannot start with 0.
currencystringNoOptional. When present it must be exactly three uppercase letters and equal the player's stored currency. eur is invalid_wallet. A different currency is unsupported_currency.
reference_transaction_idstringNoRequired for ROLLBACK. The transaction_id of a successful DEBIT or CREDIT for the same player. 1–128 characters.

Response

200Balance, or a completed transfer.

JSON
{
  "operation": "DEBIT",
  "status": "success",
  "currency": "EUR",
  "balance": "7.5",
  "transaction_id": "bet-1001"
}

Errors

HTTPerrorWhen
400invalid_walletBody, amount, operation, currency text, or rollback amount does not match.
400unsupported_currencyUppercase currency does not equal the player's currency.
403ip_not_allowedNo customer was admitted.
404player_not_foundThis customer has no mapping for player_id.
404wallet_transaction_not_foundRollback reference is unknown for this player.
409insufficient_balanceThe amount cannot be reserved.
409wallet_idempotency_conflictSame key, different request.
409wallet_transaction_pendingThat key is still pending.
409wallet_already_rolled_backThe original transaction was already reversed.
409wallet_transaction_not_reversiblePending, failed, or not a debit/credit.
413payload_too_largeBody is over 8 KiB.
502wallet_provider_failedThe provider rejected the operation.
503security_config_unavailableAPI-key policy could not be read.
503wallet_not_configuredThe wallet or provider client is not configured.
503wallet_store_unavailableThe ledger could not be used.
504wallet_provider_timeoutThe provider did not answer. The row stays pending.

BALANCE

curl
curl -sS -X POST "https://api.hzura.com/api/v1/casino/wallet" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"player_id":"player-1","operation":"BALANCE"}'
JSON response
{
  "operation": "BALANCE",
  "status": "success",
  "currency": "EUR",
  "balance": "0"
}

DEBIT

The balance is reduced before the provider is called. If the balance cannot cover the amount, the response is insufficient_balance and the provider is not called.

On provider acceptance the reduced balance stands. A definite provider rejection releases that reservation and returns wallet_provider_failed. A timeout leaves the debit pending and keeps the reserved amount.

curl
curl -sS -X POST "https://api.hzura.com/api/v1/casino/wallet" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"player_id":"player-1","operation":"DEBIT","transaction_id":"bet-1001","amount":"5.00","currency":"EUR"}'

If the wallet held 12.5 before this debit, a successful response looks like this. amount "5.00" is stored and returned in balance without trailing zeros.

JSON
{
  "operation": "DEBIT",
  "status": "success",
  "currency": "EUR",
  "balance": "7.5",
  "transaction_id": "bet-1001"
}

CREDIT

The balance increases only after the provider accepts the credit. A rejection or a timeout does not credit the wallet. A timeout still leaves the transaction_id pending.

curl
curl -sS -X POST "https://api.hzura.com/api/v1/casino/wallet" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"player_id":"player-1","operation":"CREDIT","transaction_id":"win-1001","amount":"12.50","currency":"EUR"}'
JSON response
{
  "operation": "CREDIT",
  "status": "success",
  "currency": "EUR",
  "balance": "12.5",
  "transaction_id": "win-1001"
}

ROLLBACK

Rollback reverses one successful DEBIT or CREDIT for the same player, currency, and amount. transaction_id is the rollback's own idempotency key. reference_transaction_id is the original debit or credit. The amount must equal the original amount; a mismatch is 400 invalid_wallet.

A debit is restored only after the provider accepts the rollback. A credit is reserved first and restored to the player only if the provider rejects the rollback. If that reservation cannot be taken, the response is insufficient_balance.

A second rollback of the same original transaction, under a new key, is wallet_already_rolled_back. Repeating the rollback key with the same body returns the first rollback result. Pending and failed originals cannot be rolled back (wallet_transaction_not_reversible). An unknown reference is wallet_transaction_not_found.

curl
curl -sS -X POST "https://api.hzura.com/api/v1/casino/wallet" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"player_id":"player-1","operation":"ROLLBACK","transaction_id":"rb-1001","reference_transaction_id":"bet-1001","amount":"5.00","currency":"EUR"}'
JSON response
{
  "operation": "ROLLBACK",
  "status": "success",
  "currency": "EUR",
  "balance": "12.5",
  "transaction_id": "rb-1001"
}

Idempotency and pending

transaction_id is unique per customer. Repeating the same key with the same player, operation, amount, and currency returns the original result and does not call the provider again. For a rollback, the reference and amount must match as well.

RepeatResult
Same key and same requestOriginal result. The provider is not called again.
Same key, different body409 wallet_idempotency_conflict
Same key while the first call is pending409 wallet_transaction_pending. The provider is not called again.
Same key after a definite rejectionThe original error, such as insufficient_balance or wallet_provider_failed.

504 wallet_provider_timeout means the provider did not answer and the outcome is unknown. The transaction stays pending. A pending debit keeps the reserved amount. A pending credit is not applied. Repeating the same transaction_id does not move the balance again.

Do not start a second debit or credit for the same bet with a new transaction_id while the first one is pending. That would be a different transaction. Rollback of a pending transaction is rejected.

This API does not look up a provider status for that row. Customers cannot settle a pending transaction through a public route. A timeout is not success.