Other endpoints
API · Operator → Boss HubSigned /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
| Endpoint | Scope | Module | Environment |
|---|---|---|---|
| GET /v1/limits | games.read | — | Shared |
| GET /v1/limits/rules | games.read | — | Shared |
| PUT /v1/limits/rules | limits.write | — | Shared |
| GET /v1/availability | games.read | — | Rules shared, result per environment |
| PUT /v1/availability/rules | availability.write | — | Shared |
| GET /v1/lobby/categories | games.read | — | Shared |
| PUT /v1/lobby/categories | lobby.write | — | Shared |
| GET /v1/marketing/assets | marketing.read | — | Shared |
| GET /v1/reconciliation/daily | reconciliation.read | — | Per environment |
| POST /v1/reconciliation/daily | reconciliation.write | — | Per environment |
| GET /v1/wallet-health | wallet_health.read | — | Per environment |
| GET /v1/live/stream | rounds.read | live | Per environment |
| POST /v1/player-events | player_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.
| Field | Type | Description |
|---|---|---|
| currency | ISO 4217 | Currency of the limits. |
| min_bet | decimal(18,2) | Lowest bet. |
| max_bet | decimal(18,2) | Highest bet, after the market cap. |
| default_bet | decimal(18,2) | Default bet, inside the range. |
| source | object | The 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.
{
"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.
| Order | Layer | source |
|---|---|---|
| 1 | Platform, all games | platform |
| 2 | Platform, provider | provider |
| 3 | Platform, game | game |
| 4 | Operator, all games (scope: all) | operator |
| 5 | Operator, provider | operator |
| 6 | Site, all games | site |
| 7 | Site, provider | site |
| 8 | Operator, game | operator |
| 9 | Site, game | site |
| 10 | Market cap of the site, max_bet only; converted if the currency differs | market_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.
| Field | Type | Description |
|---|---|---|
| scope | string | Target: all, provider, game. |
| ref | string | null | Provider code or game code; null for all. |
| site_id | string | null | Site code; null for an operator-wide rule. |
| currency | ISO 4217 | Currency of the rule. |
| inherit | boolean | true: the rule is kept but not applied; the upper layer applies. |
| min_bet | decimal(18,2) | null | Lowest bet. |
| max_bet | decimal(18,2) | null | Highest bet. |
| default_bet | decimal(18,2) | null | Default 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.
- 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.
{
"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.
| Field | Type | Description |
|---|---|---|
| scope | string | provider or game. |
| ref | string | Provider code or game code. |
| site_id | string | Site code. |
| enabled | boolean | Whether launch is open right now. |
| source | string | null | The 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.
| source | Meaning |
|---|---|
| maintenance | Maintenance window of the platform or the provider. |
| operator | Operator suspended, or production not approved yet. |
| site_status | Site is off, or a site in Test status was called on Live. |
| module | The providers module is off (third-party providers). |
| platform | Closed by Boss Hub. |
| access | The provider is not open to you in this environment, or the game is not in your selection. |
| game | The game is not released yet or is retired. |
| operator_rule | Your operator-wide rule is off. |
| site_rule | The site rule is off. |
| market_rule | No RTP variant is allowed in the site’s market. |
[
{ "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.
Lobby categories
GET /v1/lobby/categories · scope games.read. Returns the lobby categories in order.
| Field | Type | Description |
|---|---|---|
| key | string | Category key, e.g. featured. |
| name | object | Category name: tr, en. |
| mode | string | manual or auto. |
| auto_rule | string | null | new_30d, popular_7d, jackpot; null for manual. |
| games | string[] | 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.
[
{
"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.
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.
| Field | Type | Description |
|---|---|---|
| game_id | string | Game code. |
| zip_url | string | Signed ZIP link for the whole pack. Valid for 15 minutes. |
| files[].kind | string | tile, portrait, banner, logo, video, copy. |
| files[].size | string | null | Size or format, e.g. 1920x600. |
| files[].locale | string | null | Language of text files. |
| files[].name | string | File name. |
| files[].url | string | null | Signed 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.
[
{
"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.
| Field | Type | Description |
|---|---|---|
| date | date | The UTC day. |
| currency | ISO 4217 | Currency of the row. |
| provider_side | object | Our totals: bets, wins (decimal), rounds, transactions (integer). |
| operator_side | object | null | Your totals in the same shape; null until you send them. rounds and transactions you did not send are null. |
| difference | decimal(18,2) | null | Yours minus ours: the bets difference; if bets match, the wins difference. null until you send totals. |
| status | string | pending: 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. |
[
{
"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.
{
"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.
| Field | Type | Description |
|---|---|---|
| p50_ms | integer | Median response time, ms. Times are bucket upper bounds (e.g. 200, 250); 0 without calls. |
| p95_ms | integer | 95th percentile response time, ms. Same buckets; 0 without calls. |
| error_rate | number | Share 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_rate | number | Share 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. |
{
"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.
| Event | When |
|---|---|
| round.closed | A round closed. |
| round.rolled_back | A round was rolled back. |
| round.big_win | After the round event: the win reached the platform’s big-win multiple of the bet (50× by default). |
| jackpot.won | After round.closed: the round has a jackpot win. |
| data field | Type | Description |
|---|---|---|
| id | string | Round ID. |
| site_id | string | Site code. |
| player_id | string | Your player ID. |
| game_id | string | Game code. |
| currency | ISO 4217 | Currency of the round. |
| bet | decimal(18,2) | Bet. On a rolled-back round, the bet that was reversed. |
| win | decimal(18,2) | Total win: game, free round and jackpot wins. Wins your wallet has not confirmed yet are included. |
| status | string | closed or rolled_back. |
| kind | string | normal, freeround, bonus_buy. |
| has_jackpot | boolean | The round has a jackpot win. |
| closed_at | date-time | When 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.
: 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"}
: pingPlayer 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.
- 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.
{
"player_id": "u_88213",
"site_id": "site_mrd01",
"type": "deposit",
"amount": "25.00",
"currency": "USD",
"occurred_at": "2026-11-05T14:30:00Z"
}{
"id": "pev_01HF3Q2M8V"
}Error codes
| Code | HTTP | Endpoint | When |
|---|---|---|---|
| SCOPE_DENIED | 403 | GET /v1/limits, GET /v1/availability, PUT /v1/limits/rules, PUT /v1/availability/rules, GET /v1/wallet-health, GET /v1/live/stream, POST /v1/player-events | site_id is not one of your sites, or not your site key’s site |
| SCOPE_DENIED | 403 | PUT /v1/limits/rules, PUT /v1/availability/rules | A site key sent no site_id |
| SCOPE_DENIED | 403 | GET and PUT /v1/lobby/categories | site_id is not your site key’s site |
| SCOPE_DENIED | 403 | GET and POST /v1/reconciliation/daily | Called with a site key |
| MODULE_DISABLED | 403 | GET /v1/live/stream | The live module is off |
| FRAUD_CLOSURE | 403 | PUT /v1/availability/rules | A fraud rule closed the record; only off is accepted (details.case_id) |
| NOT_FOUND | 404 | GET /v1/limits | No such game, its provider is not open to you, or no limit in this currency |
| NOT_FOUND | 404 | PUT /v1/limits/rules, PUT /v1/availability/rules | ref not found, or its provider is not open to you |
| NOT_FOUND | 404 | GET and PUT /v1/lobby/categories | site_id is not one of your sites |
| NOT_FOUND | 404 | POST /v1/player-events | No game was opened with this player_id in this environment (on that site) |
| NOT_FOUND | 404 | zip_url download | The link expired or was altered |
| FILE_TOO_LARGE | 413 | zip_url download | The pack is larger than 500 MB |
| SITE_REQUIRED | 422 | GET /v1/limits | You have several sites and sent no site_id |
| VALIDATION_ERROR | 422 | All | Invalid parameter or body (details.fields) |
| VALIDATION_ERROR | 422 | PUT /v1/limits/rules | ref, or min_bet and max_bet, missing (details.field) |
| VALIDATION_ERROR | 422 | PUT /v1/lobby/categories | details.reason: KEY_DUPLICATE, GAME_NOT_ELIGIBLE (details.game), AUTO_RULE_REQUIRED (details.key) |
| LIMIT_RANGE_INVALID | 422 | PUT /v1/limits/rules | min_bet or max_bet is 0, or min_bet is above max_bet |
| LIMIT_DEFAULT_INVALID | 422 | PUT /v1/limits/rules | default_bet is outside the range |
| LIMIT_OUT_OF_RANGE | 422 | PUT /v1/limits/rules | Leaves the range of the upper layers (details.allowed) |
| DATE_IN_FUTURE | 422 | POST /v1/reconciliation/daily | date is after today (UTC) |