Bet
Register a player bet
Called when a player places a bet. You must deduct the bet amount from the player's balance.
Endpoint
POST /betRequest
POST /bet HTTP/1.1
Host: your.game.api
X-Marbles-Signature: <signature>
Content-Type: application/json
{
"requestId": "8df0475e-5069-483a-8205-f6089997abc9",
"transactionId": "ea0240f5-483d-434b-a8d4-04dabf61cde3",
"clientSessionId": "0k3cz83bb3h2vn53ocnc7pxw9",
"clientPlayerId": "02mnrpyv2qd9jbwhoniyimxsy",
"roundId": "17cc81fd-df13-4ca4-857d-de0f766dc372",
"gameId": "f1c0b104-f29d-44a9-ae93-e8afcbe3feb9",
"amount": 1000000,
"currency": "USD",
"meta": {
"betType": "PickWinner",
"selection": [
"40e5e0eb-cc5a-4a81-a157-7a4b641c05df",
"17fcb2c6-f0ac-4855-98ef-9e7e3fd738bd",
"bb65a881-a4fe-4b65-aae5-e085a9f96cd3"
]
},
"timestamp": "2025-06-15T14:30:00.000Z"
}Request Fields
| Field | Type | Description |
|---|---|---|
requestId | string | Unique request identifier (UUID) |
transactionId | string | Unique transaction identifier for this bet |
clientSessionId | string | The player's session identifier |
clientPlayerId | string | The player's unique identifier |
roundId | string | The game round identifier |
gameId | string | The game identifier |
amount | int64 | Bet amount with 5-digit precision |
currency | string | ISO 4217 currency code |
isFree | boolean | true if this is a freebet (see below) |
rewardUuid | string | The reward identifier for freebets |
meta | object | Additional bet metadata |
meta.betType | string | Type of bet placed |
meta.selection | array | Selected items for the bet |
timestamp | string | ISO 8601 UTC timestamp of when the request was created |
Freebet Requests
When a player uses a freebet, the request includes additional fields:
{
"requestId": "...",
"transactionId": "...",
"amount": 0,
"currency": "USD",
"isFree": true,
"rewardUuid": "promo-winter-2025-001",
"meta": { ... }
}| Field | Description |
|---|---|
amount | Always 0 for freebets (no real money deducted) |
isFree | true to indicate this is a freebet |
rewardUuid | Your clientRewardId from when you granted the freebet |
For freebets, do not deduct any balance from the player. The amount will be 0. See Freebets & Rewards for more details.
Response Contract
Always respond HTTP 200; put the outcome in status. We read the status field, not the HTTP code, to decide what happens to the bet.
status | When you return it | What 155 does |
|---|---|---|
SUCCESS | Bet accepted, stake debited | Bet is live |
INSUFFICIENT_BALANCE_ERROR | Player can't cover the stake | Bet rejected, surfaced to player |
DUPLICATE_TRANSACTION_ERROR | This transactionId was already processed | Treated as the original; no re-debit |
BET_LIMIT_REACHED_ERROR | Operator bet-limit hit | Bet rejected |
BONUS_ERROR | Free-bet/reward problem | Bet rejected |
UNKNOWN_ERROR | Unexpected operator-side failure | Bet rejected, retried |
Never return a bare failed to create bet message or a non-200 HTTP status — always return one of the status values above. ROUND_CLOSED is not a bet status: it's a 155-side condition, not something you return.
The one exception is authentication: if you verify X-Marbles-Signature and it fails, reject the request with a non-2xx (e.g. 401) — that's an auth failure, not a bet outcome. The status values above apply only to requests that passed signature verification. (A bad signature never occurs on genuine 155 traffic, which is always correctly signed, so this can't affect real bets.)
See Error codes for the canonical enum across all callbacks.
Idempotency
Replaying a /bet with the same transactionId must return DUPLICATE_TRANSACTION_ERROR with no balance change — it is a duplicate, not a new bet (network-retry safety). Do not debit the stake a second time.
This is asymmetric with /win: a replayed /win returns the original SUCCESS result, whereas a replayed /bet returns DUPLICATE_TRANSACTION_ERROR.
Aggregator (Hub88) integrations use a different status set — this page is for direct integrations.
Success Response
HTTP/1.1 200 OK
X-Marbles-Signature: <signature>
Content-Type: application/json
{
"status": "SUCCESS",
"requestId": "8df0475e-5069-483a-8205-f6089997abc9",
"clientPlayerId": "02mnrpyv2qd9jbwhoniyimxsy",
"currency": "USD",
"balance": 1000000
}Response Fields
| Field | Type | Description |
|---|---|---|
status | string | "SUCCESS" |
requestId | string | Echo back the request ID |
clientPlayerId | string | Echo back the player ID |
currency | string | ISO 4217 currency code |
balance | int64 | New balance after bet (5-digit precision) |
Error Response
HTTP/1.1 200 OK
X-Marbles-Signature: <signature>
Content-Type: application/json
{
"status": "INSUFFICIENT_BALANCE_ERROR",
"requestId": "8df0475e-5069-483a-8205-f6089997abc9",
"clientPlayerId": "02mnrpyv2qd9jbwhoniyimxsy"
}Error Statuses
| Status | Description |
|---|---|
INSUFFICIENT_BALANCE_ERROR | Player does not have enough balance |
DUPLICATE_TRANSACTION_ERROR | This transactionId was already processed (idempotent replay) |
BONUS_ERROR | Bet does not pass free-bet / reward rules |
BET_LIMIT_REACHED_ERROR | Player has reached their betting limit |
UNKNOWN_ERROR | Bet could not be registered |
For an expired or invalid player session, return UNKNOWN_ERROR. There is no dedicated session-state status on the wallet callbacks — any status outside the enum above is treated the same as UNKNOWN_ERROR (the bet is rejected and the player sees a generic failure).
See the Response Contract above for what 155 does with each status, and Error codes for the canonical enum.