# How to set up a digital wallet in Bubble.io: Step-by-Step Guide

- Tool: Bubble
- Difficulty: Beginner
- Time required: 25-30 min
- Compatibility: All Bubble plans (Stripe requires paid plan for live charges)
- Last updated: March 2026

## TL;DR

Build a digital wallet feature in Bubble by adding a balance field to the User data type, creating a Transaction data type for history, and integrating Stripe for top-ups. This tutorial covers the full wallet lifecycle — adding funds, spending credits, displaying balance, and maintaining a transaction ledger.

## Overview: Digital Wallet in Bubble

A digital wallet lets users store credits or funds inside your app, spend them on services, and view their transaction history. This tutorial builds a wallet system using Bubble's database for balance tracking and Stripe for real-money top-ups. It is designed for non-technical founders building marketplaces, SaaS apps, or platforms that need an internal currency.

## Before you start

- A Bubble account with user authentication set up
- A Stripe account (test mode is fine for development)
- The Stripe plugin installed in Bubble
- Basic understanding of Data Types and Workflows

## Step-by-step guide

### 1. Add wallet fields to the User data type

Go to Data tab → Data types → User. Add a new field called 'wallet_balance' of type number (default value: 0). This field stores the user's current credit balance. Optionally add a 'wallet_currency' text field if you support multiple currencies.

> Pro tip: Store amounts in the smallest unit (cents) to avoid floating-point issues. Display as dollars by dividing by 100.

**Expected result:** The User data type has a wallet_balance field set to 0 for new users.

### 2. Create the Transaction data type

Create a new Data Type called 'Transaction' with fields: user (User), amount (number — positive for credits, negative for debits), type (Option Set: top_up, purchase, refund, transfer), description (text), balance_after (number — the wallet balance after this transaction), and stripe_charge_id (text — for linking to Stripe payments). This provides a complete audit trail of every wallet change.

**Expected result:** A Transaction data type exists with fields for amount, type, description, and balance tracking.

### 3. Build the wallet dashboard page

Create a page called 'wallet.' At the top, add a Text element displaying 'Balance: $' followed by Current User's wallet_balance / 100 :formatted as currency. Below, add a Button labeled 'Add Funds' and a Repeating Group with data source: Do a search for Transaction (constraint: user = Current User), sorted by Created Date descending. In each cell, display the date, type, description, amount (formatted with +/- sign), and balance_after.

**Expected result:** Users see their current balance and a scrollable list of all past transactions.

### 4. Set up Stripe Checkout for adding funds

On the 'Add Funds' button, create a workflow. Add preset amount options (like $10, $25, $50) using a set of buttons or a dropdown. When the user clicks 'Add Funds' with a selected amount, the workflow action is: Charge the current user (Stripe plugin action) → Amount = selected amount in cents, Currency = usd, Description = 'Wallet top-up.' On success, add a second action: Make changes to Current User → wallet_balance = Current User's wallet_balance + amount. Then: Create a new Transaction → user = Current User, amount = the top-up amount, type = top_up, description = 'Added funds via Stripe', balance_after = Current User's wallet_balance.

**Expected result:** Users can add real money to their wallet via Stripe, and the balance and transaction history update immediately.

### 5. Create a workflow for spending wallet credits

When a user makes a purchase in your app, add wallet deduction logic to the purchase workflow. First, check if Current User's wallet_balance >= purchase amount. If yes: Make changes to Current User → wallet_balance = Current User's wallet_balance - amount. Then Create a new Transaction → amount = negative amount, type = purchase, description = item name, balance_after = Current User's wallet_balance. If insufficient balance, show an alert: 'Insufficient wallet balance. Please add funds.'

> Pro tip: Use a backend workflow for the deduction to prevent race conditions where two simultaneous purchases could overdraw the balance.

**Expected result:** Purchases deduct from the wallet balance and create a transaction record. Insufficient funds are handled gracefully.

### 6. Add privacy rules to protect wallet data

Go to Data tab → Privacy. On Transaction: add a rule 'When This Transaction's user is Current User' → allow Find in searches and View all fields. This ensures users can only see their own transactions. On the User type, ensure wallet_balance is not exposed to other users by restricting field-level visibility to the user themselves or admins.

**Expected result:** Users can only view their own wallet balance and transaction history. Other users cannot access this data.

## Complete code example

File: `Workflow summary`

```text
DIGITAL WALLET — WORKFLOW SUMMARY
==================================

DATA MODEL:
  User (modified):
    + wallet_balance (number, default: 0, stored in cents)
    + wallet_currency (text, default: "usd")

  Transaction (new):
    - user (User)
    - amount (number — positive=credit, negative=debit)
    - type (Option Set: top_up, purchase, refund, transfer)
    - description (text)
    - balance_after (number)
    - stripe_charge_id (text)

WORKFLOW: Add Funds
  Event: When "Add Funds" button is clicked
  Condition: Dropdown amount is not empty
  Action 1: Charge current user (Stripe)
    Amount: Dropdown's value × 100 (convert to cents)
    Currency: usd
  Action 2: Make changes to Current User
    wallet_balance = wallet_balance + charge amount
  Action 3: Create Transaction
    user = Current User
    amount = charge amount
    type = top_up
    description = "Added funds via Stripe"
    balance_after = Current User's wallet_balance

WORKFLOW: Spend Credits
  Event: When "Purchase" button is clicked
  Condition: Current User's wallet_balance >= item price
  Action 1: Make changes to Current User
    wallet_balance = wallet_balance - item price
  Action 2: Create Transaction
    amount = -(item price)
    type = purchase
    description = item name
    balance_after = Current User's wallet_balance
  ELSE (insufficient balance):
    Show alert: "Insufficient wallet balance"

PRIVACY:
  Transaction: user = Current User → Find + View
  User wallet_balance: visible only to self + admin
```

## Common mistakes

- **Using frontend workflows for balance deductions without backend validation** — Frontend workflows can be manipulated or run simultaneously, potentially allowing negative balances Fix: Use a backend workflow with a balance check for all deductions to prevent race conditions
- **Storing currency amounts as decimals instead of cents** — Floating-point arithmetic can cause rounding errors (e.g., $10.00 - $9.99 might not equal $0.01) Fix: Store all amounts in cents (integers) and divide by 100 only for display purposes
- **Not recording the balance_after on each transaction** — Without a running balance, you cannot audit discrepancies or debug balance issues Fix: Always store the resulting balance on each Transaction record for a complete audit trail

## Best practices

- Store all monetary values in cents to avoid floating-point rounding issues
- Use backend workflows for balance changes to prevent simultaneous deduction race conditions
- Record every balance change as a Transaction for a complete audit trail
- Add privacy rules so users can only view their own wallet and transactions
- Include a balance_after field on every transaction for easy reconciliation
- Implement a minimum top-up amount to reduce Stripe transaction fees per top-up
- Add admin tools to credit or debit user wallets manually for refunds and adjustments

## Frequently asked questions

### Can I build the wallet without Stripe?

Yes, for a virtual currency system that does not involve real money. Skip the Stripe integration and add credits manually via admin workflows or as rewards for actions.

### How do I handle refunds to the wallet?

Create a refund workflow that adds the amount back to wallet_balance and creates a Transaction with type = refund. If the original payment was via Stripe, also process a Stripe refund.

### Is storing wallet balance on the User record secure?

It is secure if you add privacy rules that prevent other users from viewing or modifying the wallet_balance field, and use backend workflows for all balance changes.

### Can users transfer credits to other users?

Yes. Create a transfer workflow that deducts from the sender's balance and adds to the recipient's balance, creating two Transaction records — one debit and one credit — both with type = transfer.

### What happens if a Stripe charge succeeds but the balance update fails?

Use Stripe webhooks to confirm successful charges. Set up a backend workflow triggered by the checkout.session.completed webhook that updates the balance, ensuring the balance only changes when payment is truly confirmed.

### Can RapidDev help build a payment and wallet system?

Yes. RapidDev has experience building complex wallet and payment systems in Bubble including multi-currency support, automated reconciliation, and fraud prevention.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/set-up-a-digital-wallet-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/set-up-a-digital-wallet-in-bubble
