155API

Rollback

Reverse a previously registered bet


155 calls your wallet (signed with X-Marbles-Signature) to reverse a previously registered /bet — for example when a round is cancelled or errors out before settlement. You must refund the stake to the player's balance.

When This Fires

/rollback only fires before /win has been sent for a given bet. Once /win is delivered (regardless of amount, including the amount: 0 loss form), the round is terminal — no /rollback will follow.

Triggers for /rollback:

  • The round was cancelled before settlement
  • The player's bet timed out during chip placement
  • /bet was received and acknowledged, but a downstream error required us to reverse the debit before the round settled
  • Your /bet failed from our side — it returned UNKNOWN_ERROR (or any unrecognised status), a non-200, or exceeded the 8-second deadline. We treat the bet as rejected and send a /rollback for that transaction to undo any debit that may have landed

You may receive a /rollback for a bet you never accepted

Because a timed-out or errored /bet also triggers a rollback, the referenceTransactionId may point at a transaction your wallet has no record of accepting — or one your wallet actually did debit even though the response never reached us. Handle both: if the bet was debited, refund it; if you have no record of it, return SUCCESS with no balance movement. Never treat an unknown referenceTransactionId as an error.

Not for Reversing Settlements

To reverse a granted-but-unused freebet, use POST /game/free-bets/rewards/cancel — not /rollback. See Freebets & Rewards.

Endpoint

POST /rollback

Request

POST /rollback 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",
  "roundClosed": true,
  "timestamp": "2025-06-15T14:30:00Z"
}

Request Fields

FieldTypeDescription
requestIdstringUnique request identifier (UUID)
transactionIdstringIdentifier for this rollback attempt. Not stable between attempts of the same rollback — never use it as your dedupe key (see Idempotency)
referenceTransactionIdstringThe original bet transaction ID being rolled back — constant across attempts; this is your dedupe key
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
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

The roundClosed field indicates whether this is the final transaction for a round:

  • roundClosed: true - This is the final transaction. The round is cancelled and no more transactions will occur.
  • roundClosed: false - Other bets in the same game round are still in flight (common in multi-chip rounds) — this rollback does not end the round.

Use roundClosed to finalize round records in your system. When true, you can safely mark the round as cancelled/voided for reporting purposes.

The Rollback-to-Zero Rule

Restore the stake — nothing more, nothing less

A /rollback refunds the stake so the balance returns to exactly what it was before the bet — restore the stake, never re-debit, never double-refund.

The net effect of /bet followed by /rollback must be zero: the player ends with the same balance they had before the bet was placed. The rollback payload carries no amount field — look up the bet identified by referenceTransactionId and refund its stake, then stop there. Do not deduct anything, and do not refund a stake that was already refunded — see Idempotency below.

Freebet Rollbacks

When the original bet was a freebet, the request includes isFree: true:

{
  "requestId": "...",
  "transactionId": "...",
  "referenceTransactionId": "...",
  "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
  • Pass isFree and rewardUuid through unchanged so the rollback maps to the correct grant
  • No balance refund needed (the original freebet had amount: 0) — mark the freebet as cancelled in your records

Rolling back an already-settled freebet is treated as a duplicate and silently deduped — return SUCCESS, balance unchanged. See Freebets & Rewards for the full reward flow.

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 rollback.

The full status set lives in Error codes — that is the canonical home for the enum across all callbacks. For /rollback the relevant outcomes are:

statusWhen you return itWhat 155 does
SUCCESSStake refunded (or already rolled back)Rollback recorded
DUPLICATE_TRANSACTION_ERRORYou already processed this rollbackAccepted exactly like SUCCESS — the rollback is recorded and not retried
UNKNOWN_ERRORUnexpected operator-side failure155 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 rollback 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 rollbacks.)

Idempotency

Networks retry, so 155 may resend a rollback it isn't certain landed. Dedupe /rollback on referenceTransactionId — the bet being refunded, which stays constant across every attempt. A replayed /rollback is treated as the original rollback: return plain SUCCESS with the balance unchanged — the stake was already restored once, and there is nothing more to refund.

Do NOT dedupe /rollback on `transactionId`

The per-request transactionId is not stable between attempts — two attempts to roll back the same bet can carry two different transactionId values with the same referenceTransactionId, and after a failed /bet you may receive several attempts within a few seconds. A wallet that dedupes rollbacks on transactionId refunds the same stake once per attempt. This is the opposite of /bet and /win, where transactionId is the dedupe key and is stable across retries.

The replay response matches /win — return SUCCESS — and is asymmetric with /bet, where a replay returns DUPLICATE_TRANSACTION_ERROR. But the dedupe key differs: /bet and /win dedupe on transactionId; /rollback dedupes on referenceTransactionId.

Worked Examples

Success — first /rollback

The stake is refunded and the player's balance returns to exactly what it was before the bet.

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 /rollback — same referenceTransactionId

155 re-sent the rollback (note: the new attempt carries a different transactionId but the same referenceTransactionId). You return the original rollback result: still SUCCESS, balance unchanged (the stake was already refunded once — do not refund 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
balanceint64Balance after rollback — equals the pre-bet balance, as an integer 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"
}

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

On this page