Seamless Wallet API
The Wallet API is the primary integration point between your casino and the Velo RGS. Your server must implement these endpoints so the RGS can debit bets, credit wins, and query balances in real time.
Authentication & Signing
All requests are signed with HMAC-SHA256. The RGS sends these headers on every call:
| Header | Description |
|---|---|
X-Api-Key | Your operator API key |
X-Sign | HMAC-SHA256(request_body, API_SECRET) |
X-Game-Id | Game identifier (e.g., velo_btc_5min) |
Content-Type | application/json |
TIP
Verify the X-Sign header on every incoming request to ensure it originated from the Velo RGS. Reject any request with an invalid signature.
Endpoints
POST /wallet/authenticate
Validate a player's session token and return their profile. Called when a player opens the game.
Request Body:
json
{
"token": "player-session-jwt-or-token",
"game_id": "velo_btc_5min"
}Response:
json
{
"player_id": "player_abc123",
"username": "JohnDoe",
"currency": "USD",
"balance": 1500.00,
"session_token": "session_xyz789"
}The session_token returned here will be included in all subsequent debit/credit/rollback requests, allowing you to validate the session is still active.
POST /wallet/debit
Debit the player's balance for a bet placement.
Request Body:
json
{
"player_id": "player_abc123",
"transaction_id": "550e8400-e29b-41d4-a716-446655440001",
"round_id": "184721",
"game_id": "velo_btc_5min",
"amount": 100.00,
"currency": "USD",
"session_token": "session_xyz789"
}Response (success):
json
{
"transaction_id": "550e8400-e29b-41d4-a716-446655440001",
"balance": 1400.00
}Idempotency
If you receive a duplicate transaction_id, return the original success response without debiting again. The RGS uses the bet UUID as the idempotency key.
POST /wallet/credit
Credit the player's balance for a win or early cashout.
Request Body:
json
{
"player_id": "player_abc123",
"transaction_id": "credit-550e8400-e29b-41d4-a716-446655440001",
"ref_transaction_id": "550e8400-e29b-41d4-a716-446655440001",
"round_id": "184721",
"game_id": "velo_btc_5min",
"amount": 182.00,
"currency": "USD",
"reason": "settle",
"is_round_finished": true,
"session_token": "session_xyz789"
}| Field | Type | Description |
|---|---|---|
transaction_id | string | Idempotency key — stable across retries. Format: credit-{bet_id} or cashout-{bet_id} |
ref_transaction_id | string | Links back to the original debit (bet) |
reason | string | "settle" (round ended) or "cashout" (early exit) |
is_round_finished | boolean | true = no more transactions for this round. false = round still active (cashout) |
Response:
json
{
"transaction_id": "550e8400-e29b-41d4-a716-446655440002",
"balance": 1582.00
}Zero-Win Credits
When a player loses, the RGS sends a credit with amount: 0.00 to explicitly close the bet on your side. This ensures every debit has a matching credit for clean reconciliation.
POST /wallet/rollback
Reverse a debit that failed to complete (e.g., bet insertion error, oracle failure).
Request Body:
json
{
"player_id": "player_abc123",
"transaction_id": "rollback-550e8400-e29b-41d4-a716-446655440001",
"ref_transaction_id": "550e8400-e29b-41d4-a716-446655440001",
"round_id": "184721",
"amount": 100.00,
"currency": "USD",
"reason": "bet_insert_failure",
"session_token": "session_xyz789"
}| Field | Type | Description |
|---|---|---|
transaction_id | string | Idempotency key — stable across retries. Format: rollback-{bet_id} |
| Rollback Reason | Description |
|---|---|
oracle_failure | Price oracle was unavailable during settlement |
bet_insert_failure | Bet was debited but failed to record in game state |
round_voided | Round cancelled due to price divergence or system error |
Response:
json
{
"transaction_id": "rollback-550e8400-e29b-41d4-a716-446655440001",
"balance": 1500.00
}POST /wallet/end_round
Signals that a round has concluded. Called after all bets are settled. This ensures the operator knows the round is closed even when no credits are issued (e.g., all players lost with zero-win credits).
Request Body:
json
{
"round_id": "184721",
"game_id": "velo_btc_5min",
"session_token": "session_xyz789"
}Response: Any 2xx response indicates success.
TIP
This endpoint is called with critical retry (10 retries over ~5 minutes). Implement idempotent handling — multiple calls for the same round_id should be safe.
POST /wallet/balance
Returns the player's current balance. Called periodically for balance display.
Request Body:
json
{
"player_id": "player_abc123",
"game_id": "velo_btc_5min"
}Response:
json
{
"balance": 1500.00
}Transaction Flow
A complete round lifecycle produces this sequence of wallet calls and corresponding iframe events:
1. Player opens game
→ POST /wallet/authenticate
← VELO_READY { gsid }
2. Player places bet ($100 on UP at 1.82x)
→ POST /wallet/debit (amount: 100.00)
← VELO_BET_PLACED { betId, side: "up", stake: 100, odds: 1.82, balance: 1400 }
3a. Player wins (round settles UP)
→ POST /wallet/credit (amount: 182.00, reason: "settle", is_round_finished: true)
← VELO_BET_SETTLED { betId, result: "win", payout: 182.00, balance: 1582 }
3b. Player loses (round settles DOWN)
→ POST /wallet/credit (amount: 0.00, reason: "settle", is_round_finished: true)
← VELO_BET_SETTLED { betId, result: "loss", payout: 0, balance: 1400 }
3c. Player cashes out early
→ POST /wallet/credit (amount: 145.00, reason: "cashout", is_round_finished: false)
← VELO_BET_SETTLED { betId, result: "cashout", payout: 145.00, balance: 1545 }Reconciliation
Every debit (bet) is paired with exactly one credit (settle or cashout). Use the betId field in VELO_BET_PLACED and VELO_BET_SETTLED to match them. The balance field in both events reflects the authoritative wallet balance after the transaction.
Early Cashout
When is_round_finished: false, the round is still running for other players. Your accounting system should keep the round open until it receives a credit with is_round_finished: true.
Error Codes
Your wallet API should return structured error responses for failures:
json
{
"error_code": "INSUFFICIENT_FUNDS",
"message": "Player balance is insufficient for this bet"
}| Error Code | HTTP Status | Description |
|---|---|---|
INSUFFICIENT_FUNDS | 400 | Player cannot afford the bet |
PLAYER_NOT_FOUND | 400 | Unknown player ID |
PLAYER_BLOCKED | 400 | Player account is suspended or blocked |
SESSION_EXPIRED | 400 | Session token is no longer valid |
DUPLICATE_TRANSACTION | 400 | Transaction already processed (return original result) |
BET_LIMIT_EXCEEDED | 400 | Bet exceeds configured limits |
TIMESTAMP_EXPIRED | 401 | Request timestamp is older than 5 minutes (replay protection) |
Retry Behavior with Jitter
The RGS uses tiered retry with exponential backoff and randomized jitter to prevent thundering herd:
- Debit, authenticate, balance — 3 retries (200ms base)
- Credit, rollback, end_round — 10 retries (500ms base, 30s max per wait)
The backoff formula:
WaitTime = min(MaxWaitTime, BaseInterval × 2^retryAttempt × Jitter)
Jitter = random(0.85 ... 1.15)The jitter ensures that if multiple sessions disconnect simultaneously, their retries arrive at slightly different intervals — preventing a recovering server from being overwhelmed.
4xx errors are never retried — the RGS reads your error_code and handles it gracefully. The transaction_id remains stable across all retry attempts, ensuring idempotency.
Currency Support
The RGS supports any currency configured by the operator. The currency field is passed through in all wallet requests and displayed in the game UI.
| Currency | Status |
|---|---|
USD | ✅ Default |
EUR | ✅ Supported |
GBP | ✅ Supported |
BRL | ✅ Supported |
| Custom | ✅ Any ISO 4217 code — the RGS passes it through to your wallet |
TIP
The player's currency is set during /wallet/authenticate. The RGS uses this currency for all subsequent debit and credit calls for that session. Amounts are always in the player's currency — no conversion happens on the RGS side.
Security Checklist
- [ ] Verify
X-SignHMAC on every request - [ ] Validate timestamp freshness (reject if >5 minutes old)
- [ ] Store
API_SECRETsecurely (env variables, vault) - [ ] Use HTTPS (TLS 1.2+) for all endpoints
- [ ] Implement idempotency on
transaction_id - [ ] Validate
session_tokenon debit/credit/rollback - [ ] Set reasonable response timeout (< 2 seconds)
- [ ] Handle
INSUFFICIENT_FUNDSgracefully on funded accounts (certification testing)
Certification Sandbox
Set WALLET_MODE=sandbox to activate an in-memory sandbox wallet with 5 pre-seeded test players ($10,000 each). The sandbox supports configurable error injection — see the Sandbox & Testing guide.