Win
Register a winning or losing bet result
155 calls your wallet (signed with X-Marbles-Signature) to register a win or loss — the settlement of a bet. For winning bets, add the win amount to the player's balance. For losing bets, the amount is 0.
Endpoint
POST /winRequest
POST /win HTTP/1.1
Host: your.game.api
X-Marbles-Signature: <signature>
Content-Type: application/json
{
"requestId": "8df0475e-5069-483a-8205-f6089997abc9",
"transactionId": "9ea48131-3a0f-4067-94d0-3212e7e25abb",
"referenceTransactionId": "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",
"roundClosed": true,
"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 win |
referenceTransactionId | string | The original bet transaction ID |
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 | Win amount (0 for losses) with 5-digit precision |
currency | string | ISO 4217 currency code |
isFree | boolean | true if the original bet was a freebet |
rewardUuid | string | The clientRewardId from the original freebet grant (only present when isFree is true) |
roundClosed | boolean | Whether this transaction closes the round (see below) |
timestamp | string | ISO 8601 UTC timestamp of when the request was created |
Round Lifecycle
The roundClosed field indicates whether this is the final transaction for a round:
roundClosed: true- This is the final transaction. No more bets, wins, or rollbacks will occur for this round.roundClosed: false- More transactions may follow for this round (e.g., multi-bet rounds).
Use roundClosed to finalize round records in your system. When true, you can safely mark the round as complete for reporting and reconciliation purposes. No /rollback will be sent for a bet after its /win callback — /win (including the amount: 0 loss form) is the terminal callback for that bet.
Win vs Loss
- Win:
amount > 0- Add this amount to the player's balance - Loss:
amount = 0- No balance change needed (bet was already deducted)
Freebet Results
When the original bet was a freebet, the request includes:
{
"requestId": "...",
"transactionId": "...",
"referenceTransactionId": "...",
"amount": 1500000,
"currency": "USD",
"isFree": true,
"rewardUuid": "promo-winter-2025-001",
"roundClosed": true
}isFreeistrueto indicate the original bet was a freebetrewardUuidcontains yourclientRewardIdfor tracking which promotion this freebet belongs to- For wins: Credit the
amountas real money to the player - For losses:
amountis0, no action needed
Freebet winnings are real money. When a freebet wins, credit the full win amount to the player's balance. 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 settlement.
The full status set lives in Error codes — that is the canonical home for the enum across all callbacks. For /win the relevant outcomes are:
status | When you return it | What 155 does |
|---|---|---|
SUCCESS | Win/loss settled, balance updated | Settlement recorded |
BONUS_ERROR | Free-bet/reward settlement problem | Settlement rejected |
UNKNOWN_ERROR | Unexpected operator-side failure | 155 retries |
Never return a non-200 HTTP status or a bare error body — always respond 200 with one of the status values above. A non-200 is read as a transport failure and may trigger retries before the body is parsed.
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 win outcome. The status values above apply only to requests that passed signature verification. (A bad signature never occurs on genuine 155 traffic, so this can't affect real wins.)
Idempotency
Networks retry, so 155 may resend a callback it isn't certain landed. Dedupe by transactionId so a retry never moves money twice. The returned status for a replay differs by callback — this is the most common point of confusion:
| Callback | Replay of the same transactionId | Returned status | Balance effect |
|---|---|---|---|
/bet | Rejected as a duplicate bet | DUPLICATE_TRANSACTION_ERROR | unchanged |
/win | Treated as the original settlement | SUCCESS | unchanged |
/rollback | Treated as the original rollback | SUCCESS | unchanged |
The asymmetry is deliberate. A replayed /bet is surfaced as DUPLICATE_TRANSACTION_ERROR — a duplicate is not a new bet, and flagging it tells 155 the stake was already debited. A replayed /win or /rollback returns plain SUCCESS: the settlement is simply re-confirmed, the money already moved once, and there is nothing to flag. In both cases the balance is unchanged — return success without crediting again; do not credit the win a second time and do not cancel the original credit.
Worked Examples
Success — first /win
The win settles and the player's balance reflects the credit.
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
}Replayed /win — same transactionId
155 resent the callback. You return the original settlement result: still SUCCESS, balance unchanged (you do not credit the win again).
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 win/loss (5-digit precision) |
Error Response
HTTP/1.1 200 OK
X-Marbles-Signature: <signature>
Content-Type: application/json
{
"status": "UNKNOWN_ERROR",
"requestId": "8df0475e-5069-483a-8205-f6089997abc9",
"clientPlayerId": "02mnrpyv2qd9jbwhoniyimxsy"
}Common Mistakes
- Returning
DUPLICATE_TRANSACTION_ERRORon a/winreplay. That is the/betrule. A replayed/winreturnsSUCCESS(see Idempotency). - Re-crediting on a replay. The money already moved on the first
/win; a replay must not add the win amount again, and must not reverse the original credit. - Returning a non-200 HTTP status (or a bare error body). Always respond
200with the outcome instatus.
See the Response Contract above for what 155 does with each status, and Error codes for the canonical enum.