155API

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 /win

Request

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:00Z"
}

Request Fields

FieldTypeDescription
requestIdstringUnique request identifier (UUID)
transactionIdstringUnique transaction identifier for this win
referenceTransactionIdstringThe original bet transaction ID
clientSessionIdstringThe player's session identifier
clientPlayerIdstringThe player's unique identifier
roundIdstringPer-bet round reference — the same value this bet carried on /bet. Unique per bet, not per game round (see Round IDs)
gameIdstringThe game identifier
amountint64Win amount (0 for losses), an integer in the currency's wire precision (see Currencies)
currencystringISO 4217 currency code
isFreebooleantrue if the original bet was a freebet
rewardUuidstringThe clientRewardId from the original freebet grant (only present when isFree is true)
roundClosedbooleanWhether this transaction closes the round (see below)
timestampstringRFC 3339 UTC timestamp of when the request was created. Fractional seconds vary by callback — parse leniently, do not pin an exact format string

Round Lifecycle

On /win, roundClosed is always true — each /win settles and closes its own per-bet round, and no further transactions follow for that bet. (The true/false distinction only matters on /rollback.)

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
}
  • isFree is true to indicate the original bet was a freebet
  • rewardUuid contains your clientRewardId for tracking which promotion this freebet belongs to
  • For wins: Credit the amount as real money to the player
  • For losses: amount is 0, 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:

statusWhen you return itWhat 155 does
SUCCESSWin/loss settled, balance updatedSettlement recorded
DUPLICATE_TRANSACTION_ERRORYou already applied this exact transactionIdAccepted exactly like SUCCESS — recorded, not retried. Return it only for a genuinely already-applied transaction; returning it for one you did not apply permanently strands the payout
UNKNOWN_ERRORUnexpected operator-side failure155 retries

/win recognises only SUCCESS and DUPLICATE_TRANSACTION_ERROR as applied. Any other status — including BONUS_ERROR — or a non-200 or timeout means the settlement was not recorded: the same /win, with the same transactionId, will be re-sent periodically until you accept it. Re-sends can continue for hours, and a settlement can also be re-delivered much later (e.g. after an outage) — your transactionId dedupe must not expire quickly. See Settlement timing & 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:

CallbackDedupe keyReplay behaviourReturned statusBalance effect
/bettransactionIdRejected as a duplicate betDUPLICATE_TRANSACTION_ERRORunchanged
/wintransactionIdTreated as the original settlementSUCCESS (DUPLICATE_TRANSACTION_ERROR also accepted)unchanged
/rollbackreferenceTransactionIdTreated as the original rollbackSUCCESS (DUPLICATE_TRANSACTION_ERROR also accepted)unchanged

/rollback dedupes on a different key

On /bet and /win the transactionId is stable across retries and is your dedupe key. On /rollback it is not stable between attempts — dedupe rollbacks on referenceTransactionId instead. See /rollback § Idempotency.

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

FieldTypeDescription
statusstring"SUCCESS"
requestIdstringEcho back the request ID
clientPlayerIdstringEcho back the player ID
currencystringISO 4217 currency code
balanceint64New balance after win/loss, in the currency's wire precision (see Currencies)

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

  • Rejecting a /win replay. A replayed /win returns SUCCESS (preferred) — DUPLICATE_TRANSACTION_ERROR is also accepted as applied. What you must never do is treat the replay as a failure (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 200 with the outcome in status.

See the Response Contract above for what 155 does with each status, and Error codes for the canonical enum.

On this page