Skip to content

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:

HeaderDescription
X-Api-KeyYour operator API key
X-SignHMAC-SHA256(request_body, API_SECRET)
X-Game-IdGame identifier (e.g., velo_btc_5min)
Content-Typeapplication/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"
}
FieldTypeDescription
transaction_idstringIdempotency key — stable across retries. Format: credit-{bet_id} or cashout-{bet_id}
ref_transaction_idstringLinks back to the original debit (bet)
reasonstring"settle" (round ended) or "cashout" (early exit)
is_round_finishedbooleantrue = 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"
}
FieldTypeDescription
transaction_idstringIdempotency key — stable across retries. Format: rollback-{bet_id}
Rollback ReasonDescription
oracle_failurePrice oracle was unavailable during settlement
bet_insert_failureBet was debited but failed to record in game state
round_voidedRound 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 CodeHTTP StatusDescription
INSUFFICIENT_FUNDS400Player cannot afford the bet
PLAYER_NOT_FOUND400Unknown player ID
PLAYER_BLOCKED400Player account is suspended or blocked
SESSION_EXPIRED400Session token is no longer valid
DUPLICATE_TRANSACTION400Transaction already processed (return original result)
BET_LIMIT_EXCEEDED400Bet exceeds configured limits
TIMESTAMP_EXPIRED401Request 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.

CurrencyStatus
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-Sign HMAC on every request
  • [ ] Validate timestamp freshness (reject if >5 minutes old)
  • [ ] Store API_SECRET securely (env variables, vault)
  • [ ] Use HTTPS (TLS 1.2+) for all endpoints
  • [ ] Implement idempotency on transaction_id
  • [ ] Validate session_token on debit/credit/rollback
  • [ ] Set reasonable response timeout (< 2 seconds)
  • [ ] Handle INSUFFICIENT_FUNDS gracefully 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.

B2B Integration Documentation