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
/betwas received and acknowledged, but a downstream error required us to reverse the debit before the round settled
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 /rollbackRequest
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:00.000Z"
}Request Fields
| Field | Type | Description |
|---|---|---|
requestId | string | Unique request identifier (UUID) |
transactionId | string | Unique transaction identifier for this rollback |
referenceTransactionId | string | The original bet transaction ID being rolled back |
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 |
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. The round is cancelled and no more transactions will occur.roundClosed: false- More transactions may follow (rare for rollbacks, but possible in multi-bet scenarios).
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. Refund the original stake (the amount from the referenced /bet) and 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
}isFreeistrueto indicate the original bet was a freebetrewardUuidcontains yourclientRewardIdfor tracking which promotion this freebet belongs to- Pass
isFreeandrewardUuidthrough 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:
status | When you return it | What 155 does |
|---|---|---|
SUCCESS | Stake refunded (or already rolled back) | Rollback recorded |
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 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 callback it isn't certain landed. Dedupe by transactionId so a replay never refunds the stake twice. 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.
This matches /win, which uses the same success-dedupe rule, and is asymmetric with /bet: a replayed /bet returns DUPLICATE_TRANSACTION_ERROR, whereas a replayed /rollback (like /win) returns SUCCESS.
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 transactionId
155 resent the callback. 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
| 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 | Balance after rollback — equals the pre-bet balance (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"
}See the Response Contract above for what 155 does with each status, and Error codes for the canonical enum.