Boss HubBoss HubDocs
ChangelogStatus
Provider API/Other endpoints

Other endpoints

API · Operator → Boss Hub

Signed /v1 endpoints not covered on the other pages: bet limits, availability, lobby categories, marketing assets, daily reconciliation, wallet health, the live round stream and player events. Each section gives the scope, the inputs, the response and the behaviour.

Endpoints

EndpointScopeModuleEnvironment
GET /v1/limitsgames.read—Shared
GET /v1/limits/rulesgames.read—Shared
PUT /v1/limits/ruleslimits.write—Shared
GET /v1/availabilitygames.read—Rules shared, result per environment
PUT /v1/availability/rulesavailability.write—Shared
GET /v1/lobby/categoriesgames.read—Shared
PUT /v1/lobby/categorieslobby.write—Shared
GET /v1/marketing/assetsmarketing.read—Shared
GET /v1/reconciliation/dailyreconciliation.read—Per environment
POST /v1/reconciliation/dailyreconciliation.write—Per environment
GET /v1/wallet-healthwallet_health.read—Per environment
GET /v1/live/streamrounds.readlivePer environment
POST /v1/player-eventsplayer_events.write—Per environment

Common rules

  • Sign requests as described in Authentication. Write requests (PUT, POST) also need X-Request-Id.
  • site_id is always the site code, e.g. site_mrd01. A key bound to a site sees only its own site and writes only to it.
  • Amounts in responses are JSON numbers with two decimals, e.g. 0.20.
  • Shared data is the same in Test and Live: a change made with a Test key also applies on Live. See Environments.
  • Errors that any signed endpoint can return (INVALID_SIGNATURE, TIMESTAMP_SKEW, IP_NOT_ALLOWED, SCOPE_MISSING, RATE_LIMITED, and on writes 422 and 409 for X-Request-Id) are on the Error codes page. Codes specific to this page are in the table at the bottom.

Effective limits

GET /v1/limits · scope games.read. Returns the limits a launch of the game would get on the site: all rules and the market cap applied.

game_idstringrequired
Game code, e.g. sultans-ember. At most 120 characters.
site_idstring
Site code. Required with an operator key if you have several sites; a site key uses its own site.
currencyISO 4217
USD (default), EUR, TRY.
FieldTypeDescription
currencyISO 4217Currency of the limits.
min_betdecimal(18,2)Lowest bet.
max_betdecimal(18,2)Highest bet, after the market cap.
default_betdecimal(18,2)Default bet, inside the range.
sourceobjectThe layer that set min_bet and max_bet: platform, provider, game, operator, site, market_rule.

Returns 404 NOT_FOUND if the game does not exist, its provider is not open to you, or no limit is defined in this currency. Whether the game is open is not checked here; use GET /v1/availability for that.

200Effective limits
{
  "currency": "USD",
  "min_bet": 0.20,
  "max_bet": 50.00,
  "default_bet": 1.00,
  "source": { "min_bet": "platform", "max_bet": "site" }
}

Limit order

Layers apply from top to bottom. Each layer can only narrow the range above it: min_bet only goes up and max_bet only goes down. A layer that would leave an empty range is ignored. default_bet comes from the last layer that sets one and is fitted into the range; if no layer sets one, it is min_bet. Boss Hub manages the platform layers; the operator and site layers are yours.

OrderLayersource
1Platform, all gamesplatform
2Platform, providerprovider
3Platform, gamegame
4Operator, all games (scope: all)operator
5Operator, provideroperator
6Site, all gamessite
7Site, providersite
8Operator, gameoperator
9Site, gamesite
10Market cap of the site, max_bet only; converted if the currency differsmarket_rule

Your limit rules

GET /v1/limits/rules · scope games.read. Takes no parameters. Returns the limit rules of your operator and sites: operator rules first, then site rules. Platform rules are not listed. A site key sees only the rules of its own site.

FieldTypeDescription
scopestringTarget: all, provider, game.
refstring | nullProvider code or game code; null for all.
site_idstring | nullSite code; null for an operator-wide rule.
currencyISO 4217Currency of the rule.
inheritbooleantrue: the rule is kept but not applied; the upper layer applies.
min_betdecimal(18,2) | nullLowest bet.
max_betdecimal(18,2) | nullHighest bet.
default_betdecimal(18,2) | nullDefault bet; null if not set.

Writing a limit rule

PUT /v1/limits/rules · scope limits.write. Writes one rule: one target, one level (operator or site), one currency. The rule is created if missing, updated otherwise. The response is {"changed": true}, or false if nothing changed.

scopestringrequired
all, provider, game.
refstring
Provider code for provider, game code for game. Required for these two, ignored for all. At most 120 characters.
site_idstring | null
Site code: the rule applies only to this site. null or omitted: operator-wide. A site key must send its own site code.
currencyISO 4217required
USD, EUR, TRY.
inheritboolean
true: drop your own values for this target so the upper layer applies. See below.
min_betdecimal(18,2)
Required unless inherit is true. Greater than 0. JSON number or string, at most two decimals.
max_betdecimal(18,2)
Required unless inherit is true. Not lower than min_bet.
default_betdecimal(18,2) | null
Must be between min_bet and max_bet. Omitted or null: the rule has no default of its own.
Writes it whole: Each PUT writes all three values of the rule together; an omitted default_bet clears the saved default. The values must stay inside the range of the upper layers, otherwise you get 422 LIMIT_OUT_OF_RANGE with details.allowed. The rule is shared: it changes in Test and Live together, new launches get the new values at once, and the limits.changed webhook is sent.
  • scope: all with inherit: true deletes the rule.
  • provider or game with inherit: true keeps the rule and its values but stops applying them; the GET /v1/limits/rules row shows inherit: true. A new PUT with values applies the rule again. If there is no rule, the response is changed: false.
PUTRequest body
{
  "scope": "game",
  "ref": "sultans-ember",
  "site_id": "site_mrd01",
  "currency": "USD",
  "min_bet": 0.20,
  "max_bet": 50.00,
  "default_bet": 1.00
}

Availability

GET /v1/availability · scope games.read. Returns the resolved state, per site, of every provider open to you and of its games. It is the same check as launch and runs in your key’s environment.

site_idstring
Site code. All your sites if omitted; a site key gets its own site.
providerstring
Provider code. Only this provider and its games.
FieldTypeDescription
scopestringprovider or game.
refstringProvider code or game code.
site_idstringSite code.
enabledbooleanWhether launch is open right now.
sourcestring | nullThe first layer that closes it; null when open.

For each site, provider rows come first, then game rows. Game rows are the games that have a live version and are not retired. If you work with selected games, a game outside your selection comes back with enabled: false and source: access.

sourceMeaning
maintenanceMaintenance window of the platform or the provider.
operatorOperator suspended, or production not approved yet.
site_statusSite is off, or a site in Test status was called on Live.
moduleThe providers module is off (third-party providers).
platformClosed by Boss Hub.
accessThe provider is not open to you in this environment, or the game is not in your selection.
gameThe game is not released yet or is retired.
operator_ruleYour operator-wide rule is off.
site_ruleThe site rule is off.
market_ruleNo RTP variant is allowed in the site’s market.
200States
[
  { "scope": "provider", "ref": "boss-originals", "site_id": "site_mrd01", "enabled": true, "source": null },
  { "scope": "game", "ref": "sultans-ember", "site_id": "site_mrd01", "enabled": false, "source": "operator_rule" }
]

Opening and closing rule

PUT /v1/availability/rules · scope availability.write. Writes your decision for a provider or a game: operator-wide or for one site. The response is {"changed": true}, or false if the state was already the same.

scopestringrequired
provider, game.
refstringrequired
Provider code or game code. At most 120 characters.
site_idstring | null
Site code: the decision applies only to this site. null or omitted: operator-wide. A site key must send its own site code.
statestringrequired
off closes. on and inherit leave it open unless an upper level closes it; inherit follows the upper level.
Precedence: The order is platform, operator, site; at each level the provider rule comes before the game rule. An off at any of them closes the game and no lower level can open it: on in a site rule does not override an operator off. A record closed by a fraud rule cannot be opened through the API (403 FRAUD_CLOSURE). The rule is shared: it applies in Test and Live together, and the game.availability_changed webhook is sent.

Lobby categories

GET /v1/lobby/categories · scope games.read. Returns the lobby categories in order.

site_idstring
Site code. Returns the site’s own set; if the site has none, the operator-wide set. If omitted, the operator-wide set; a site key gets its own site.
FieldTypeDescription
keystringCategory key, e.g. featured.
nameobjectCategory name: tr, en.
modestringmanual or auto.
auto_rulestring | nullnew_30d, popular_7d, jackpot; null for manual.
gamesstring[]Game codes, in order. The rule fills an auto category.
  • new_30d: games released in the last 30 days.
  • popular_7d: games played in the last 7 days.
  • jackpot: games in a jackpot pool you take part in.
  • An automatic category takes only live games in your library, at most 24. They are ordered by rounds in the last 7 days (in your key’s environment), then by name.
200Categories
[
  {
    "key": "featured",
    "name": { "tr": "Öne çıkanlar", "en": "Featured" },
    "mode": "manual",
    "auto_rule": null,
    "games": ["sultans-ember", "cyber-djinn"]
  },
  {
    "key": "new",
    "name": { "tr": "Yeni oyunlar", "en": "New games" },
    "mode": "auto",
    "auto_rule": "new_30d",
    "games": ["cyber-djinn"]
  }
]

Saving lobby categories

PUT /v1/lobby/categories · scope lobby.write. The body is the full list of categories (a JSON array) and replaces the whole target set: operator-wide, or the site in site_id. The list order is the lobby order. The response is the saved set, in the GET format.

site_idstring
Query parameter. Site code. Operator-wide set if omitted; a site key writes to its own site.
[].keystringrequired
1-40 characters: a-z, 0-9, _ and -. Must be unique in the list.
[].nameobjectrequired
tr and en; 1-60 characters each.
[].modestringrequired
manual, auto.
[].auto_rulestring | null
Required for auto: new_30d, popular_7d, jackpot. Ignored for manual.
[].gamesstring[]
For manual, game codes in order; at most 500, duplicates are dropped. Not stored for auto. Every code must be a game in your library.
Full replace: Categories missing from the list are deleted. An empty list ([]) deletes the site’s own set; the site then shows the operator-wide set again. Categories are shared: they are the same in Test and Live.

Marketing assets

GET /v1/marketing/assets · scope marketing.read. Lists the asset packs of games in your library. The pack of an announced game appears 14 days before its release.

game_idstring
Game code. Only this game’s pack; an empty list if it has none.
FieldTypeDescription
game_idstringGame code.
zip_urlstringSigned ZIP link for the whole pack. Valid for 15 minutes.
files[].kindstringtile, portrait, banner, logo, video, copy.
files[].sizestring | nullSize or format, e.g. 1920x600.
files[].localestring | nullLanguage of text files.
files[].namestringFile name.
files[].urlstring | nullSigned link to the single file, valid for 5 minutes. null if the file is not in storage; the file is still listed.

zip_url is a ready download link (…/packs/<game>.zip?op=…&exp=…&sig=…), valid for 15 minutes. This download needs no signature headers; the link itself is signed for your operator and that game. An expired or altered link returns 404 NOT_FOUND. The ZIP holds the files in storage and a manifest.json that lists every asset with an included flag. Call the list again for a fresh link.

200Asset packs
[
  {
    "game_id": "sultans-ember",
    "zip_url": "https://api.example.com/…/packs/sultans-ember.zip?op=…&exp=1762344900&sig=…",
    "files": [
      {
        "kind": "banner",
        "size": "1920x600",
        "locale": null,
        "name": "sultans-ember_banner_1920x600.png",
        "url": "https://api.example.com/files/fil_01HF3K9QZ2?exp=1762344300&sig=5d0e8b13"
      },
      {
        "kind": "copy",
        "size": null,
        "locale": "en",
        "name": "sultans-ember_copy_en.txt",
        "url": null
      }
    ]
  }
]

Daily reconciliation

GET /v1/reconciliation/daily · scope reconciliation.read. Compares our totals for one UTC day with the totals you sent, one row per currency. Operator keys only: a site key gets 403 SCOPE_DENIED.

datedaterequired
UTC day, e.g. 2026-11-05.
Counting: A transaction counts on the UTC day of its created_at. Only settled transactions count: ok, manual_ok, reversed. Amounts are gross: a bet rolled back later still counts on its own day, and the rollback adds to the transaction count. Free rounds, jackpot wins and promotion credits are included. rounds counts rounds with a bet. Our side is recalculated on every read. A day with no activity and no totals from you returns [].
FieldTypeDescription
datedateThe UTC day.
currencyISO 4217Currency of the row.
provider_sideobjectOur totals: bets, wins (decimal), rounds, transactions (integer).
operator_sideobject | nullYour totals in the same shape; null until you send them. rounds and transactions you did not send are null.
differencedecimal(18,2) | nullYours minus ours: the bets difference; if bets match, the wins difference. null until you send totals.
statusstringpending: no totals from you. mismatch: bets or wins differ, or rounds or transactions differ if you sent them. matched: they match, or the difference was closed manually in the portal.
200Daily rows
[
  {
    "date": "2026-11-05",
    "currency": "USD",
    "provider_side": { "bets": 51240.00, "wins": 49190.40, "rounds": 19377, "transactions": 39102 },
    "operator_side": { "bets": 51240.00, "wins": 49185.40, "rounds": 19377, "transactions": null },
    "difference": -5.00,
    "status": "mismatch"
  }
]

Sending daily totals

POST /v1/reconciliation/daily?date=YYYY-MM-DD · scope reconciliation.write. You send your own totals for one day and currency. The response is the compared row: 200, a single object in the format above. Sending again for the same day and currency replaces your previous totals and reopens a difference closed manually in the portal. Operator keys only.

datedaterequired
Query parameter. UTC day; today or earlier. A future day gets 422 DATE_IN_FUTURE.
currencyISO 4217required
USD, EUR, TRY.
betsdecimal(18,2)required
Your total bets. JSON number or string, at most two decimals, not negative.
winsdecimal(18,2)required
Your total wins, same format.
roundsinteger
Number of rounds with a bet. Compared if sent.
transactionsinteger
Number of transactions, rollbacks included. Compared if sent.
POSTRequest body
{
  "currency": "USD",
  "bets": 51240.00,
  "wins": 49185.40,
  "rounds": 19377
}

Wallet health

GET /v1/wallet-health · scope wallet_health.read. Returns the performance of the callbacks we sent to your wallet, in your key’s environment. Test suite and connection test calls are not counted. Status thresholds come from your account’s wallet alert rules, or the platform defaults.

site_idstring
Site code: this site only. Operator totals if omitted; a site key gets its own site.
windowstring
24h (default), 7d, 30d. Applies to the totals and by_call; hourly always covers the last 24 hours.
FieldTypeDescription
p50_msintegerMedian response time, ms. Times are bucket upper bounds (e.g. 200, 250); 0 without calls.
p95_msinteger95th percentile response time, ms. Same buckets; 0 without calls.
error_ratenumberShare of failed calls, 0-1. A failure is a timeout, a connection error, a non-200 reply, an unreadable body, or an error code other than a business rejection. INSUFFICIENT_FUNDS, LIMIT_EXCEEDED, PLAYER_BLOCKED, INVALID_TOKEN, TRANSACTION_ROLLED_BACK, DUPLICATE_TRANSACTION are not failures.
timeout_ratenumberShare of calls that timed out, 0-1.
by_call[]object[]One row each for authenticate, balance, bet, win, rollback: call, count, p95_ms, error_rate.
hourly[]object[]24 rows, oldest first: hour (start of the hour, UTC) and status. bad: the error or timeout rate went over its threshold. warn: p95 went over its threshold. ok: otherwise, and for hours without calls.
200Metrics (hourly cut to 2 of 24 rows)
{
  "p50_ms": 75,
  "p95_ms": 250,
  "error_rate": 0.0004,
  "timeout_rate": 0.0001,
  "by_call": [
    { "call": "authenticate", "count": 1204, "p95_ms": 150, "error_rate": 0 },
    { "call": "balance", "count": 3310, "p95_ms": 125, "error_rate": 0 },
    { "call": "bet", "count": 18420, "p95_ms": 250, "error_rate": 0.0005 },
    { "call": "win", "count": 6120, "p95_ms": 200, "error_rate": 0.0002 },
    { "call": "rollback", "count": 12, "p95_ms": 300, "error_rate": 0 }
  ],
  "hourly": [
    { "hour": "2026-11-04T15:00:00.000Z", "status": "ok" },
    { "hour": "2026-11-04T16:00:00.000Z", "status": "warn" }
  ]
}

Live stream

GET /v1/live/stream · scope rounds.read · live module. A Server-Sent Events stream (text/event-stream) that sends your rounds as they close, in your key’s environment. Sign the request like any GET; the connection then stays open.

site_idstring
Site code: this site only. All your sites if omitted; a site key gets its own site.
EventWhen
round.closedA round closed.
round.rolled_backA round was rolled back.
round.big_winAfter the round event: the win reached the platform’s big-win multiple of the bet (50× by default).
jackpot.wonAfter round.closed: the round has a jackpot win.
data fieldTypeDescription
idstringRound ID.
site_idstringSite code.
player_idstringYour player ID.
game_idstringGame code.
currencyISO 4217Currency of the round.
betdecimal(18,2)Bet. On a rolled-back round, the bet that was reversed.
windecimal(18,2)Total win: game, free round and jackpot wins. Wins your wallet has not confirmed yet are included.
statusstringclosed or rolled_back.
kindstringnormal, freeround, bonus_buy.
has_jackpotbooleanThe round has a jackpot win.
closed_atdate-timeWhen the round closed; its start time if it has no close time.
  • The first line is the comment : ok; a : ping comment follows every 20 s. Ignore comment lines.
  • Events carry no id: and are not sent later: rounds that close while you are disconnected do not reach the stream. After reconnecting, read the rounds in between with round lookup.
  • If your client reads too slowly, events are skipped and a line that is not SSE-framed, {"type":"lag","dropped":N}, is written to the stream; your parser should ignore it. If it keeps falling behind, the connection is closed. If the key is revoked, the connection closes within about 15 s.
  • Promotion credit rounds are not sent.
  • Errors before the stream starts (signature, scope, module, site_id) come back as a normal JSON error body.
200text/event-stream
: ok

event: round.closed
data: {"id":"rnd_01HF3K9QZ2","site_id":"site_mrd01","player_id":"u_88213","game_id":"sultans-ember","currency":"USD","bet":2.00,"win":150.00,"status":"closed","kind":"normal","has_jackpot":false,"closed_at":"2026-11-05T14:22:09.000Z"}

event: round.big_win
data: {"id":"rnd_01HF3K9QZ2","site_id":"site_mrd01","player_id":"u_88213","game_id":"sultans-ember","currency":"USD","bet":2.00,"win":150.00,"status":"closed","kind":"normal","has_jackpot":false,"closed_at":"2026-11-05T14:22:09.000Z"}

: ping

Player events

POST /v1/player-events · scope player_events.write. Optional. Records a deposit, withdrawal or signal for a player who has already opened a game in this environment. The response is 201 with the event ID. If you do not send events, the metrics below stay empty.

player_idstringrequired
Your player ID, the value you sent at launch.
site_idstring
Site code. The player is looked up on this site; a site key uses its own site.
typestringrequired
deposit, withdrawal, signal.
amountstring
Amount as a string, e.g. "25.00": digits, at most two decimals. A JSON integer such as 25 is rejected.
currencyISO 4217
USD, EUR, TRY.
dataobject
Free-form JSON object.
occurred_atdate-time
When it happened. Now if omitted.
  • withdrawal: fraud rules that look for a withdrawal shortly after a bonus buy or a free round.
  • deposit: in the portal, the share of free round players who deposit afterwards.
  • signal: a data.text string is added to the player’s risk signals; data.code: "withdrawal_after_freeround" feeds the free round fraud rule.
POSTRequest body
{
  "player_id": "u_88213",
  "site_id": "site_mrd01",
  "type": "deposit",
  "amount": "25.00",
  "currency": "USD",
  "occurred_at": "2026-11-05T14:30:00Z"
}
201Recorded
{
  "id": "pev_01HF3Q2M8V"
}

Error codes

CodeHTTPEndpointWhen
SCOPE_DENIED403GET /v1/limits, GET /v1/availability, PUT /v1/limits/rules, PUT /v1/availability/rules, GET /v1/wallet-health, GET /v1/live/stream, POST /v1/player-eventssite_id is not one of your sites, or not your site key’s site
SCOPE_DENIED403PUT /v1/limits/rules, PUT /v1/availability/rulesA site key sent no site_id
SCOPE_DENIED403GET and PUT /v1/lobby/categoriessite_id is not your site key’s site
SCOPE_DENIED403GET and POST /v1/reconciliation/dailyCalled with a site key
MODULE_DISABLED403GET /v1/live/streamThe live module is off
FRAUD_CLOSURE403PUT /v1/availability/rulesA fraud rule closed the record; only off is accepted (details.case_id)
NOT_FOUND404GET /v1/limitsNo such game, its provider is not open to you, or no limit in this currency
NOT_FOUND404PUT /v1/limits/rules, PUT /v1/availability/rulesref not found, or its provider is not open to you
NOT_FOUND404GET and PUT /v1/lobby/categoriessite_id is not one of your sites
NOT_FOUND404POST /v1/player-eventsNo game was opened with this player_id in this environment (on that site)
NOT_FOUND404zip_url downloadThe link expired or was altered
FILE_TOO_LARGE413zip_url downloadThe pack is larger than 500 MB
SITE_REQUIRED422GET /v1/limitsYou have several sites and sent no site_id
VALIDATION_ERROR422AllInvalid parameter or body (details.fields)
VALIDATION_ERROR422PUT /v1/limits/rulesref, or min_bet and max_bet, missing (details.field)
VALIDATION_ERROR422PUT /v1/lobby/categoriesdetails.reason: KEY_DUPLICATE, GAME_NOT_ELIGIBLE (details.game), AUTO_RULE_REQUIRED (details.key)
LIMIT_RANGE_INVALID422PUT /v1/limits/rulesmin_bet or max_bet is 0, or min_bet is above max_bet
LIMIT_DEFAULT_INVALID422PUT /v1/limits/rulesdefault_bet is outside the range
LIMIT_OUT_OF_RANGE422PUT /v1/limits/rulesLeaves the range of the upper layers (details.allowed)
DATE_IN_FUTURE422POST /v1/reconciliation/dailydate is after today (UTC)
← PreviousGGR reportsNext →Error codes
Other endpoints · Documentation · Boss Hub