Rollback and Retry Logic
This page describes the critical requirements for rollback handling and retry behavior for all transaction types.
What a Rollback Is (and Is Not)
A rollback (type: rollback) reverses a bet placement, and only a bet placement.
GR8 Tech sends it when a placement fails due to a technical error, a timeout, or the placement retries being exhausted. The rollback returns the stake that the placement debited, and the bet ends up never placed.
Because of that, context.parentId on a rollback always points to a placement transaction: a withdrawal with reason bet, bet with tax, or freebet.
A rollback is never a settlement reversal
Reverting a settlement is a different operation with a different name: cancel settle (type: withdrawal, reason: cancelsettle). It is not a rollback, it does not carry a parentId, and it must not be routed through your rollback handler.
Rollback Requirements
Critical: Rollback Error Handling Proper rollback handling is MANDATORY for system integrity. If a rollback cannot be processed, you MUST return one of these specific error codes:
decline.parent.notfound- Parent transaction does not exist in your systemdecline.parent.failed- Parent transaction exists but failed (e.g., insufficient funds)
Never return generic errors for rollback failures. The system relies on these specific codes to handle rollback scenarios correctly.
Rollback Is Retried 400 Times If your wallet returns anything other than HTTP 200 or HTTP 400 with a valid error body for a rollback request, the system retries every 5 minutes for up to 400 attempts (~33 hours) until it receives a definitive response.
Why? The system must confirm the final state of the transaction. Temporary errors (429, 5XX, timeouts, network issues) cannot leave transactions in an uncertain state.
Action required: Ensure your rollback endpoint is highly available and always returns either:
- HTTP 200 with success response
- HTTP 400 with
decline.parent.notfoundordecline.parent.failed
Rollback Validation Requirements
When processing a rollback transaction (type: rollback):
- Verify parent transaction exists using
context.parentId— the parent is always the bet placement transaction, never a settlement - Check parent transaction status:
- If parent not found → Return
decline.parent.notfound - If parent failed → Return
decline.parent.failed - If parent succeeded → Process rollback normally
- If parent not found → Return
Rollback Example
Standard bet rollback:
{
"id": "5f338453-6172-491f-b8f0-27e382ea05eb_rollback",
"currency": "USD",
"platform": "sport",
"type": "rollback",
"createdAt": "2025-01-29T00:35:10Z",
"initiatedAt": "2025-01-29T00:35:10Z",
"context": {
"product": "sportsbook",
"reason": "sport rollback",
"betId": "5f338453-6172-491f-b8f0-27e382ea05eb",
"parentId": "5f338453-6172-491f-b8f0-27e382ea05eb"
},
"amountBreakdown": {
"cash": "13.9",
"locked": "0",
"bonus": "0"
}
}{
"id": "5f338453-6172-491f-b8f0-27e382ea05eb_rollback",
"currency": "USD",
"platform": "sport",
"type": "rollback",
"createdAt": "2025-01-29T00:35:10Z",
"initiatedAt": "2025-01-29T00:35:10Z",
"context": {
"product": "sportsbook",
"reason": "sport rollback",
"betId": "5f338453-6172-491f-b8f0-27e382ea05eb",
"parentId": "5f338453-6172-491f-b8f0-27e382ea05eb"
},
"amountBreakdown": {
"cash": "13.9",
"locked": "0",
"bonus": "0"
},
"balances": {
"sport": {
"main": {
"USD": {
"cash": "100.0",
"bonus": "0",
"locked": "0",
"retract": "0"
}
},
"sportsbook": {
"USD": {
"cash": "100.0",
"bonus": "0",
"locked": "0",
"retract": "0"
}
}
}
},
"alreadyProcessed": false
}Error response if parent not found:
{
"error": {
"code": "decline.parent.notfound",
"message": "Parent transaction 5f338453-6172-491f-b8f0-27e382ea05eb not found",
"origin": "YourCompanyName"
},
"alreadyProcessed": false
}Error response if parent failed:
{
"error": {
"code": "decline.parent.failed",
"message": "Parent transaction 5f338453-6172-491f-b8f0-27e382ea05eb failed with insufficient funds",
"origin": "YourCompanyName"
},
"alreadyProcessed": false
}Retry Logic by Operation Type
Bet Placement (withdrawal)
Limited retries - Strict time limits for bet acceptance.
Response handling:
200→ Transaction successful, bet accepted400with correct error body → Transaction declined (e.g., insufficient funds), no retries429,5XXstatus codes or timeouts → Retry up to 3 times- After 3 failed retries → System initiates rollback request
Retry parameters for bet placement:
- Retry count: 3 attempts
- Triggered by:
429,5XXstatus codes or request timeouts - After retries exhausted → Rollback initiated
Rollback retry parameters:
- Retry count: 400 attempts
- Delay between retries: 5 minutes
200or400with correct body → Retry process ends- Other responses → Continue retrying until a definitive response or the budget is exhausted
Rollback Retries Are Bounded Rollback requests are retried every 5 minutes for up to 400 attempts (~33 hours), until we receive HTTP 200 or HTTP 400 with a valid error. Make sure your rollback endpoint is highly available: if the budget is exhausted, your wallet and the bet state can go out of sync. The bet is then marked as broken on the GR8 Tech side and the operation has to be retried manually by request to our team.
Parent transaction validation:
Your wallet must verify that the parent transaction (via context.parentId) exists. Return 400 with error code decline.parent.notfound if parent transaction is not found, or decline.parent.failed if parent transaction failed.
Settlement Operations
Includes: settle, cancelsettle, resettle, cashout. The direction of the transaction (deposit or withdrawal) does not change how the response is handled.
Response handling:
200→ Transaction successful, no retries400with correct error body → Transaction declined, no retries429,5XXstatus codes or timeouts → Retry with the parameters below
Retry parameters:
- Retry count: 1000 attempts
- Delay between retries: 1 minute
- Triggered by:
429,5XXstatus codes or request timeouts - If 1000 retries reached → Bet blocked for operations until manual intervention by operations team
Bonus Operations (award/release)
Includes: bonus award, bonus release, freebet award, etc.
Retry parameters:
- Retry count: 100
- Delay between retries: 5 minutes
Response handling:
200or400with correct body → Transaction processed completely, no retries429,5XXor408status codes → Retry until success- Other responses → Retry with above parameters
Response Requirements Summary
| Operation Type | Success Response | Error Response | Retry Behavior |
|---|---|---|---|
| Bet Placement | HTTP 200 | HTTP 400 | 3 retries on 429/5XX/timeout, then rollback |
| Rollback (reverses a placement) | HTTP 200 | HTTP 400 with decline.parent.* | 400 retries on 429/5XX/timeout (5 min delay) |
Settlement (settle, cancelsettle, resettle) | HTTP 200 | HTTP 400 | 1000 retries on 429/5XX/timeout (1 min delay) |
| Bonus | HTTP 200 | HTTP 400 | 100 retries, 5 min delay |
Always Return Definitive Responses For all operations, always return either HTTP 200 (success) or HTTP 400 (business error) with a valid error body. Avoid 429 and 5XX errors or timeouts as they trigger retries.
When to use 5XX responses:
Use HTTP 5XX only when absolutely necessary, such as:
- Race condition scenario: A rollback request arrives while the parent transaction (bet placement) is still being processed due to technical delays. In this case, return HTTP 5XX to trigger retries until the parent transaction completes.
- Temporary system unavailability: Database connection issues, service temporarily down, etc.
Do NOT use 5XX for:
- Business logic errors (use HTTP 400 instead)
- Validation failures (use HTTP 400 instead)
- Parent transaction not found (use HTTP 400 with
decline.parent.notfound) - Parent transaction failed (use HTTP 400 with
decline.parent.failed)
Related Documentation
- Perform Transaction - Main transaction endpoint documentation
- Transaction Examples - Request/response examples
- Transaction Types Reference - Complete type and reason mapping
- Wallet Error Codes - Complete error code reference