Reelgate Operator API

The API your casino backend calls to list games, open game sessions and read the ledger.

Signing every request

Header Value
X-Reelgate-Key the brand API key
X-Reelgate-Timestamp unix time in seconds; must be within 300 s of our clock
X-Reelgate-Signature hex HMAC-SHA256(secret, <timestamp>\n<METHOD>\n<path?query>\n<raw body>)

Node.js:

const crypto = require('crypto');
async function reelgate(method, pathWithQuery, body) {
  const raw = body ? JSON.stringify(body) : '';
  const ts = Math.floor(Date.now() / 1000).toString();
  const sig = crypto.createHmac('sha256', process.env.REELGATE_SECRET)
    .update(`${ts}\n${method}\n${pathWithQuery}\n${raw}`).digest('hex');
  const res = await fetch(`https://reelgate.code-matrix.tech${pathWithQuery}`, {
    method,
    headers: { 'Content-Type': 'application/json', 'X-Reelgate-Key': process.env.REELGATE_KEY,
               'X-Reelgate-Timestamp': ts, 'X-Reelgate-Signature': sig },
    body: raw || undefined,
  });
  return res.json();
}

PHP:

$raw = $body ? json_encode($body) : '';
$ts  = (string) time();
$sig = hash_hmac('sha256', "$ts\n$method\n$pathWithQuery\n$raw", $secret);

Errors

Every error has the same shape and a matching HTTP status:

{ "error": { "code": "GAME_DISABLED", "message": "Game is disabled for this brand" } }
Code HTTP Meaning
INVALID_KEY 401 unknown API key
BAD_TIMESTAMP 401 timestamp missing or more than 300 s off
BAD_SIGNATURE 401 signature does not match (check path, query and body bytes)
BRAND_INACTIVE 403 the brand is suspended
IP_NOT_ALLOWED 403 source IP not on the brand allow-list
MISSING_PARAM / INVALID_MODE / INVALID_AMOUNT 422 bad input
NOT_FOUND 404 no such player, session, game or round
GAME_NOT_FOUND / GAME_DISABLED / PROVIDER_DISABLED 404 / 404 / 403 the game is not offered to this brand
CURRENCY_NOT_ALLOWED 422 the currency is not enabled on the brand
CURRENCY_NOT_SUPPORTED 422 this game does not run in that currency (see currencies on the game)
DEMO_DISABLED / DEMO_NOT_AVAILABLE 403 / 422 demo is switched off or the game has no demo
KYB_NOT_APPROVED 403 real-money play waits for KYB approval of this brand
OUT_OF_CREDIT 403 the company credit is used up (top up with your account manager)
WALLET_NOT_CONFIGURED 403 seamless brand without a wallet URL
LAUNCH_FAILED 502 the game provider did not open the game; retry or pick another game
WRONG_WALLET_MODE 422 deposit/withdraw called on a seamless brand
INSUFFICIENT_FUNDS 422 transfer brand: not enough player balance

Endpoints

GET /api/v1/ping

This call checks your keys and shows whether real play is open.

{ "ok": true, "brand": "acme-com", "company": "acme", "wallet_mode": "seamless",
  "currencies": ["USD","EUR"], "kyb_status": "approved", "real_play": true, "refusal": null,
  "time": "2026-11-06T10:00:00Z" }

refusal names the reason real play is closed: BRAND_INACTIVE, KYB_NOT_APPROVED, OUT_OF_CREDIT or WALLET_NOT_CONFIGURED.

GET /api/v1/providers

This call lists the game studios available to your brand, each with enabled (the brand's effective switch).

GET /api/v1/games

Query parameters:

Param
provider provider key from /providers
q search in the name, or an exact game id
type game type (slots, live, table, ...)
demo=true only games with a demo
live=true only live-dealer games
limit 1 to 200, default 50
cursor the next value from the previous page

Only games enabled for the brand are returned. Each game:

{ "id": 10421, "name": "Book of Gold", "provider": "booming_games", "studio": "Booming Games",
  "type": "slots", "category": "video_slots", "thumbnail_url": "https://...",
  "has_demo": true, "has_freespins": true, "has_jackpot": false, "is_live": false, "mobile": true,
  "rtp": 96.1, "volatility": "high", "max_win_multiplier": 5000,
  "currencies": ["USD","EUR"], "languages": ["en","de","pt"],
  "settings": { "enabled": true, "demo_enabled": true, "min_bet_usd": null, "max_bet_usd": null, "extra": {} } }

currencies lists every currency the game can run in. If a currency is not on that list, a session launch in it is refused.

GET /api/v1/games/:id

This call returns one game, shaped like the list items above.

POST /api/v1/sessions

This call opens a game for a player and returns the URL to load in an iframe or a new window.

{ "player_id": "u-1842", "game_id": 10421, "currency": "EUR", "mode": "real",
  "language": "en", "device": "mobile", "exit_url": "https://acme.com/lobby",
  "cashier_url": "https://acme.com/cashier", "nickname": "lucky7", "country": "DE",
  "player_ip": "203.0.113.9" }

Response 201:

{ "session": { "token": "rgt_...", "url": "https://...", "mode": "real", "status": "open",
  "currency": "EUR", "game_id": 10421, "provider": "booming_games", "player_id": "u-1842",
  "created_at": "...", "ended_at": null } }

Opening a new session closes the player's previous open session on the same brand, so a player plays one game at a time.

GET /api/v1/sessions/:token and POST /api/v1/sessions/:token/close

The first call reads a session. The second closes it: a closed session refuses new stakes, but wins and refunds from rounds already in play still settle.

Players

GET /api/v1/transactions

This is the ledger: every money leg, newest first.

{ "transactions": [ { "id": 9312, "tx_id": "rg-5521-bet", "kind": "bet", "amount": "1", "currency": "EUR",
  "amount_usd": "1.08", "round_id": "...", "ref_tx_id": null, "player_id": "u-1842", "game_id": 10421,
  "provider": "booming_games", "status": "ok", "balance_after": "99", "error": null, "latency_ms": 41,
  "attempts": 0, "is_test": false, "created_at": "..." } ], "next": "9300" }

GET /api/v1/rounds/:round_id

This call returns every leg of one round, oldest first.

GET /api/v1/reports/ggr?from=&to=&group=day|provider|game

This call returns GGR for the brand, in USD and per currency.

GET /api/v1/billing

This call shows the company credit:

{ "credit_usd": 5000.0, "charged_usd": 812.4, "credit_left_usd": 4187.6, "blocks_at_zero": true }

Free spins

Free spins run at the provider. Players do not pay for the spins. Whatever they win counts as a promo win, and it reaches your wallet as a normal win credit with "promo": true. Free spins only work on brands that are open for real play. You set the casino's caps in the portal under Game settings: free spins on or off, the max spins per player and the max bet per spin. Every grant is checked against those caps.

GET /api/v1/freespins/providers

This call lists the providers that can deliver free spins. Each row has enabled, the number of eligible games, spins_max, days_max and notes.

GET /api/v1/freespins/games?provider=&currency=&q=

This call lists the games of that provider that take free spins. When you pass currency, each game also shows its bet_steps.

GET /api/v1/freespins/options?currency=EUR&game_ids=10421,10422

Call this before you grant. It returns what you can give for these games together:

{ "currency": "EUR", "provider": "booming_games", "mixed_providers": false,
  "games": [ { "id": 10421, "name": "Book of Gold", "ok": true, "reason": null, "bet_steps": ["0.2","0.5","1"], "spin_counts": [] } ],
  "bet_steps": ["0.2","0.5"], "bet_steps_all": ["0.2","0.5","1"], "spin_counts": [],
  "spins_max": 500, "days_max": 90, "notes": null,
  "casino_limits": { "max_spins": 50, "max_bet_usd": 0.6 }, "usd_rate": 1.08 }

POST /api/v1/freespins

This call gives free spins to one player.

{ "reference": "fs-u1842-welcome", "player_id": "u-1842", "game_ids": [10421], "spins": 20,
  "bet": "0.2", "currency": "EUR", "valid_days": 7 }

reference is your id for the grant, and the call is idempotent by it. Response 201 (or 422 with status: "failed" and error when the provider refuses):

{ "freespins": { "reference": "fs-u1842-welcome", "player_id": "u-1842", "provider": "booming_games",
  "game_ids": [10421], "games": [ { "id": 10421, "name": "Book of Gold" } ], "spins": 20, "spins_used": 0,
  "spins_left": 20, "bet": "0.2", "currency": "EUR", "total_bet": "4.0", "win_total": "0.0", "win_total_usd": 0.0,
  "status": "active", "error": null, "expires_at": "...", "created_by": "api:acme-com", "created_at": "...", "finished_at": null } }

status is one of active, finished, expired, cancelled or failed.

Campaigns

A campaign is one offer that many players receive: the same games, spins, bet and validity for everyone.

Provider campaigns (tournaments, prize drops)

Some providers run their own promotions: tournaments, prize drops, missions and cash drops, often monthly and on a set of their games. The provider pays these prizes, not you. A prize reaches your wallet as a normal win credit with "promo": false and three extra fields:

{ "action": "win", "amount": "25.00", "promo": false,
  "prize_type": "tournament", "prize_campaign": "November Spins Race", "prize_funded_by": "provider" }

prize_type is one of tournament, prize_drop, mission, cash_drop, jackpot_drop, cashback, bonus_card or promo. prize_campaign is the campaign name when the provider sends one (it can be null). Credit the win like any other.

Whether your players take part is the Provider promotions switch in the portal (Settings, per company or brand). Pragmatic Play, Funky Games, Wicked Games and Arrows Edge (jackpots) are told on every session, so a change applies from the next game launch. For other providers we set it at the provider. The portal's Promotions → Provider campaigns tab lists what Pragmatic is running now for your currencies and every prize paid to your players, per campaign.

Error codes: INVALID_SPINS, INVALID_BET, BET_ABOVE_LIMIT, INVALID_DAYS, GAME_NOT_FOUND, GAME_NOT_ELIGIBLE, MIXED_PROVIDERS, PROVIDER_NOT_SUPPORTED, CURRENCY_NOT_ALLOWED, DUPLICATE_REFERENCE, INVALID_REFERENCE, TOO_MANY_PLAYERS, PLAYER_TEST, MISSING_PARAM.

How billing works

  1. You prepay credit.
  2. Every month we charge a share of the GGR your brands make on each provider (bets minus wins minus refunds; a negative month charges nothing).
  3. The share per provider is agreed in your contract. A price change applies only from its start date, so past charges never move.
  4. Promo wins (free-spin wins) are shown apart. GGR after promo = GGR before promo − promo wins. Your contract sets, per provider, whether we bill on GGR before promo (promo wins are charged, the default) or after promo (promo wins are deducted). The portal's Promotions page and Billing invoice show both numbers.
  5. Provider prizes (tournaments, prize drops, see Provider campaigns) are on their own line too. By default they lower the GGR like any win (deduct). Your contract can instead say we bill on the GGR before them (charge).
  6. When blocks_at_zero is true and the credit runs out, real-money launches are refused with OUT_OF_CREDIT. Demo play continues.