• wallet
  • transaction ledger
  • reconciliation
  • idempotency

Designing an iGaming Wallet: Make Every Balance Explainable

Designing an iGaming Wallet: Make Every Balance Explainable

Design a wallet that can explain deposits, holds, stakes, payouts and corrections from durable records. Work through balanced postings, atomic spending decisions, replay-safe operations and reconciliation with concrete review criteria.

A wallet is reliable when the team can answer a precise question: why is this amount available now, and which committed operations explain it? A balance column cannot answer that after a lost response, overlapping stakes or a late correction. A journal can help, but only if it is part of the same controlled write path that decides whether money may move.

This guide is for architects, engineering leads and finance or operations reviewers. It proposes an operational ledger, works through its entries, and identifies the evidence needed to trust it. The account model and amounts are illustrative. An operator’s finance and compliance specialists must approve the real account mapping, promotional treatment, safeguarding rules and correction policy; an engineering design does not settle those questions.

Define the wallet’s authority and the facts it must preserve

The wallet owns monetary postings and reservations. Payments supplies accepted provider evidence; games supply accepted round and settlement information; bonuses supply the funding rules and promotion reference. These modules request operations through the wallet boundary. They do not each maintain an independently writable player balance. Broader scope is covered by iGaming architecture services and payment and identity integrations.

Keep an operation distinct from its journal. The operation records intent, identity and outcome; a posting group contains the debit and credit entries for a completed monetary change. A hold reserves spending capacity without necessarily completing that change. A declined request may have an operation record and no financial entries. Recording a request is not proof that it posted.

  • Balanced posting: every committed group balances debits and credits within its currency and accounting boundary.
  • Controlled availability: spending and new holds cannot exceed eligible funds under the approved rules.
  • Stable identity: repeating the same accepted operation cannot create another financial effect; changing its meaning must be detected.
  • Preserved history: corrections add linked records. Application users cannot overwrite or delete committed entries.
  • Traceable recovery: each external reference, hold resolution and adjustment connects to its originating operation.

These are proposed acceptance conditions, not properties obtained simply by naming a service “ledger”. Administrative privileges, imports and support adjustments must respect the same conditions as ordinary game and payment requests.

Choose account types and exact amounts before designing a balance

From the operator’s perspective, player cash represents an amount owed to the player. In the illustrative model, that liability grows with credits and shrinks with debits. A debit is therefore not synonymous with “money leaving the business”; its meaning depends on the account type.

TigerBeetle’s accounting guide explains that asset balances increase with debits, liabilities increase with credits, and a transaction has both debit and credit entries. This supports the accounting vocabulary; it does not prescribe the operator’s chart of accounts or revenue recognition.

For the examples below, use a player cash liability, a PSP clearing asset for amounts held with or receivable from the processor, and a game settlement control account. The last is an operational counterpart, not automatically gaming revenue. The posting sequence below starts from zero balances, uses EUR and omits fees and tax. Other scenarios state their opening balances. Real mappings need finance approval and separate treatment of settlement timing, fees and other obligations.

Store a currency and a defined unit with each amount. An integer number of supported minor units or a decimal type with explicit precision and rounding rules can preserve exact values; binary floating point is unsuitable for authoritative monetary totals. Do not assume every supported currency or asset uses two decimal places. Validate input scale, bounds and conversion to the stored unit before accepting the operation.

PostgreSQL’s numeric documentation distinguishes exact decimal values from inexact floating point and notes that declared decimal scale can round input. Exact storage does not replace an explicit policy for excess input precision. This is a database example, not a requirement to use PostgreSQL.

Keep cash and restricted bonus value distinguishable by account and funding reference. A displayed combined total is not necessarily spendable or withdrawable. For the simple cash model, posted cash is credits minus debits; available cash is posted cash minus active cash holds. This formula assumes no permitted overdraft and no further cash restrictions. Actual action eligibility may reduce the amount usable for a particular game or withdrawal. Do not net different currencies or unrelated promotional rights into that formula.

Follow deposits, holds and settlements through their postings

Use this proposed operations checklist to connect each action to its records. It uses full hold resolution; partial settlement requires a separately defined allocation rule.

  1. Deposit EUR 100. Once the agreed evidence authorises crediting, debit PSP clearing EUR 100 and credit player cash EUR 100 in one posting group. Cash is EUR 100. Reference the accepted payment and external transaction; a browser return page cannot authorise this posting.
  2. Reserve a EUR 30 stake. Create a hold against the player’s cash and record its funding purpose. In this model the hold creates no posted debit or credit: cash stays EUR 100, held cash is EUR 30 and available cash is EUR 70. The journal and reservation history must both be explainable.
  3. Release that hold if the stake was definitively not accepted. Append the release record linked to the hold. Cash remains EUR 100 and available cash returns to EUR 100. A release is not a new EUR 30 deposit.
  4. Alternatively, commit the accepted stake. Debit player cash EUR 30 and credit game settlement control EUR 30 while resolving the hold in the same atomic wallet operation. Cash and available cash become EUR 70; the EUR 30 must not remain counted as an active hold as well.
  5. Settle with a total return of EUR 45. Debit game settlement control EUR 45 and credit player cash EUR 45, referencing the original accepted round. Cash becomes EUR 115. The example’s return includes the stake; adding another stake refund would overcredit.
  6. Request a EUR 40 withdrawal. Reserve EUR 40 under the approved withdrawal rules. Posted cash remains EUR 115, held cash is EUR 40 and available cash is EUR 75. A confirmed completed payout debits player cash EUR 40 and credits PSP clearing EUR 40 while consuming the hold. Cash is then EUR 75, with no remaining hold.
  7. Reverse the EUR 45 return if a validated correction requires it. Add a new group debiting player cash EUR 45 and crediting game settlement control EUR 45. With no intervening spending beyond the completed withdrawal, cash becomes EUR 30. Keep the original return and link the correction to it; handle any replacement settlement as another explicit operation.

The release and stake-commit branches are alternatives. A rejected or cancelled payout can release its hold only when the contract establishes that payment did not and will not occur. An unknown provider result must not be treated as rejection just because a local timer expired.

TigerBeetle’s two-phase transfer documentation gives one concrete model: reserve, then post or void using a new immutable transfer, with configured expiry support. That local mechanism cannot establish whether an external payout completed. Choose expiry rules around the actual external acceptance and recovery contract.

Commit the spending decision, operation and entries together

Suppose available cash is EUR 60 and two distinct EUR 40 requests arrive together. Both can pass a preliminary balance read. Only an authoritative atomic acceptance decision can prevent both from spending the same capacity: after one hold succeeds, available cash is EUR 20 and the other must fail or wait for a genuinely changed balance.

For a relational implementation, use a transaction that validates the operation’s scope and parameters, protects the affected balance and hold state, checks availability, writes all entries or reservation changes, and records the outcome together. Choose explicit row locking with a consistent lock order, conditional updates tied to a version and invariant, or an appropriate serializable design. A lock on an unrelated request row does not protect a player’s shared funds. A per-account queue must also deal with competing producers and worker recovery; it is not automatically a global lock.

PostgreSQL’s isolation documentation explains that serializable execution makes committed concurrent transactions equivalent to a serial order, while applications must handle serialization failures. Such protection is local to that database transaction; it does not serialize a remote provider call with the wallet.

Keep external calls outside the short transaction protecting wallet funds. Persist the intended external work and recover it under a stable operation identity after local commit. If a database transaction must restart after a deadlock or serialization conflict, repeat its full local decision under the same operation identity; do not repeat a provider payment as an accidental side effect of a transaction retry.

Scope duplicate protection to a trusted caller or integration, operation kind and stable request identity. Bind that identity to the player, account, currency, amount, funding allocation and relevant original reference. A repeated event identifier and a repeated business operation are different cases: two messages can refer to the same settlement. Resolve the financial identity at the authoritative boundary.

The Amazon Builders’ Library describes caller-provided identifiers, atomic recording with mutations, and rejection when the same identifier carries changed parameters. For a wallet, recording a token before the entries, or entries before the token, leaves a failure gap unless they commit together.

Concurrent duplicates must converge on the recorded operation through enforced uniqueness and the posting transaction. After a lost response, an authorised lookup or safe repeat should identify the original outcome, not merely report “already exists”. Persist sufficient financial references beyond any short API response cache; late replay must not become a fresh posting. A deliberately new correction gets its own identity and a link to the original.

Correct history without hiding a shortfall

An append-only journal preserves committed entries; it does not make every changing operational field immutable. A workflow status or derived balance can change under controlled transitions. The original posting group, amount, accounts and references should not be edited to make the history look like the newest result. The application’s write restrictions, privileged access controls and recovery evidence must support that rule.

A correction is a financial decision with an authority, reason and reference. Verify the originating provider or authorised staff action, identify what is being reversed, and constrain duplicate or excessive reversals. For partial reversals, the sum already reversed plus the new reversal must not exceed the eligible original amount. Check that condition atomically against other corrections; an administrator label does not exempt the operation.

Consider a variant of the example: after cash reaches EUR 75, the player spends another EUR 50, leaving EUR 25, and the EUR 45 return is then reversed. Simply subtracting it produces negative EUR 20, contrary to this model’s no-overdraft rule. Neither discarding the correction nor quietly forcing the balance to zero explains the missing amount.

If approved policy permits a financial resolution using the remaining EUR 25, an illustrative group can debit player cash EUR 25, debit a finance-approved loss or receivable account EUR 20, and credit game settlement control EUR 45, with a case reference. Cash reaches zero and the shortfall remains recorded. A receivable must represent a valid approved claim, not an engineering invention. If the policy does not permit that resolution, preserve the correction as unresolved work and escalate it; do not claim it has posted. Define account restrictions, notifications and subsequent recovery with the operator’s responsible specialists.

Cash, bonus and mixed-funded operations add another constraint: a correction must follow the original funding allocation and promotion rules. A reversal of a restricted bonus-funded stake must not silently become withdrawable cash. Staff tools should propose supported adjustment operations with reasons and required review; they should not expose a direct balance editor.

Reconcile records at matching boundaries

Reconciliation asks whether independently recorded facts agree at the same boundary. Begin with internal checks: balanced posting groups, no orphan entries, hold resolutions linked to actual holds, operation outcomes consistent with postings, and stored balance projections consistent with the journal and active reservations. Run comparisons from a coherent snapshot or explicit matching positions; comparing a live journal with an older projection creates false differences.

Then compare accepted payment records, wallet operations and provider or settlement reports. Match stable references first, then currency, amount, status and the relevant period. A provider’s payment report and its bank settlement report may describe different boundaries; fees, chargebacks and settlement timing need explicit categories. A single total cannot reveal a missing EUR 100 credit offset by an unrelated extra EUR 100 credit.

  • Provider accepted, wallet posting absent: establish the authoritative payment outcome, locate the original wallet operation, and finish that operation only under the crediting policy.
  • Wallet posting present, response absent: restore the operation’s visible result; do not add another posting to repair a status.
  • Withdrawal outcome unknown, hold still active: investigate the original provider submission and retain the reservation until the recovery rules authorise resolution.
  • Internal entries balance but external totals differ: inspect missing, repeated or misclassified operations, fees and cutoff timing. Balanced books can still record the wrong business facts.

Each discrepancy needs an owner, amount at risk, age, supporting references and a permitted resolution. Record an adjustment only after its cause and authority are established. Treat unexplained drift as an incident according to agreed thresholds; clearing it with an anonymous “reconciliation adjustment” makes the number match while destroying the explanation.

Prove recovery and cut over without creating a second wallet

Review the wallet through representative operations and failure points. Ask the team to reconstruct one deposit, one reserved stake, one completed payout and one correction from records, including both debit and credit entries where money posted. Demand evidence that a cached display can be rebuilt without becoming a second writer.

For recovery, establish which committed point the database or ledger restore reaches, then compare it with external operations that may have completed after that point. A restored local database cannot rewind a provider payout. Preserve and reconcile the intervening evidence before enabling new spending; replay must distinguish missing local effects from already completed ones. Define acceptable data loss and recovery time from actual obligations and test them rather than promising zero by default.

A migration needs the same discipline. Reconstruct opening balances and active holds, preserve their provenance and external references, and classify unresolved operations. Reconcile the imported starting position against the old system and independent evidence at a documented cutoff. Use one authoritative writer for each account during handover; merely mirroring requests into two ledgers can duplicate real effects or diverge on failure. Verify how to recover new writes before allowing rollback to the old writer.

Capacity work should measure the financial path: concurrent hot accounts, lock waits or conflicts, committed posting throughput, pending-operation age and recovery under a backlog. Move read-heavy reporting into controlled projections where appropriate, but do not authorise spending from a stale read replica. A ledger that balances during an isolated happy-path demo has not yet passed the concurrency and recovery checks below.

Extend the review with payment outcome and reconciliation design, sportsbook funding and settlement, and security boundaries and privileged controls.

Account restrictions, promotions and module coordination affect what the ledger is asked to record. Keep their contracts visible through player account architecture, bonus engine design, and the complete player and money journey. The wallet remains responsible for enforcing its financial invariants when those modules request a change.

  • Lost response and changed payload. Commit a deposit, lose the response, and submit concurrent repeats under the original identity. Prove one balanced posting group and an authorised retrieval of its result. Repeat with a changed amount, currency or player: it must not mutate or recreate the accepted operation.
  • Competing spending and hold resolution. With EUR 60 available, send two distinct EUR 40 requests. Prove that both cannot consume the same funds. Then race release and consumption of the winning hold: exactly one valid resolution may complete, without a retained duplicate hold or double return.
  • Late and excessive correction. Reverse the EUR 45 return after only EUR 25 remains under the example’s no-overdraft policy. Show the approved shortfall resolution or an explicit unresolved case. Also race partial reversal requests whose combined amount exceeds the original: the invariant must hold.
  • Restore with external work still completed. Recover to a local point before a provider payout’s recorded outcome, while the provider has already paid. Reconcile the original reference before reopening spending. Rebuild balance views and compare them at matching positions; restoring or replaying must not issue another payout.
Is a double-entry ledger enough to guarantee a correct wallet?

No. Equal debits and credits check accounting structure, not whether the payment was genuine, the amount was correct or the player could spend it. Wrong or repeated business operations can also balance. Combine balanced groups with trusted acceptance evidence, stable operation identities, atomic availability checks and reconciliation.

Must the wallet recompute every balance from all historical entries?

No. A controlled projection or cumulative balance can support efficient reads and spending checks if its authoritative update is atomic with the entries and holds it represents. Retain enough journal history and provenance to verify or rebuild it. A separately updated cache or stale replica cannot make an authoritative acceptance decision.

Should every hold automatically expire?

Only when expiry is safe under that operation’s contract. A pending local reservation does not reveal whether an external stake or payout was accepted. Expiry must prevent later acceptance or establish nonacceptance before funds become available again. Otherwise retain an explicit unknown outcome and resolve it through lookup, reconciliation or controlled review.

Does append-only storage remove the need for privileged-access controls?

No. Committed entries must be protected in the actual write path, imports, staff tools and database administration. Keep authorised corrections separate from deletion or rewriting, and record who approved them and why. Retention, personal-data treatment and accounting obligations require an explicit policy; append-only is not a reason to copy sensitive documents into every entry.

Review the evidence behind your wallet balance

Bring an operation contract, representative entries and one unresolved payment or correction. We can scope a review of account mapping, atomic acceptance, hold resolution and reconciliation, with concrete demonstrations and decisions assigned to the responsible teams.

We use cookies to ensure the security and proper functioning of our website. With your consent, we also use non-essential cookies for analytics and advertising purposes. You can accept or reject the use of non-essential cookies. You can change your preferences at any time. Learn more in our Cookie Policy.