Customer Wallets & Bonus Credits
Every customer has a single wallet balance (wallet_balance) that funds rides. This guide covers how the wallet works, how operators can adjust it, how auto top-up is configured, and how refunds interact with the wallet.
The Wallet Balance
There is one effective balance per customer: wallet balance. All manual adjustments (credits, bonuses, fees, debits) and automated flows (ride charges, refunds, auto top-ups) increase or decrease this single balance.
You'll also see a bonus column in the customer list and customer detail page. This is a legacy display-only field populated by customer imports — it is not consumed separately during ride payment and is not modified by the dashboard "Add Bonus" action. Treat it as historical context, not a live balance.
How Payments Are Applied to a Ride
Active subscription or package is applied
If the customer has an active subscription or ride package, the ride is funded by the plan with no wallet charge.
Wallet is debited
For pay-per-ride customers, the wallet is debited for the ride total (including tax and any out-of-zone fees).
Card covers any shortfall
If the wallet cannot cover the full ride, the remainder is charged to the customer's default payment method. An auto top-up may also fire here (see below).
Minimum Balance to Start a Ride
Customers must have at least $0.50 in the wallet to start a ride, unless they qualify for an exemption.
Wallet-check exemption (start a ride with $0 wallet): the customer must have both
- An active subscription or an active ride package with remaining rides/minutes, and
- A saved payment method on file.
Negative Balances
The wallet is allowed to go negative. This happens when:
- A Charge Fee is applied that exceeds current balance.
- A ride cost exceeds the wallet balance and the card charge fails.
- Operator uses Reduce Balance for an amount greater than current balance.
When Charge Fee causes the balance to cross from positive to negative, the customer automatically receives a push notification informing them of the negative balance.
Accessing Wallet Information
Customer List
The list shows each customer's wallet balance and the legacy bonus amount (if any) in separate columns.
Customer Detail Page
Navigate to Dashboard > Customers > [Customer] to see:
- Current wallet balance and bonus amount
- A Wallet dropdown in the action bar with: Add Bonus, Charge Fee, Reduce Balance
- A View Wallet Activity link to the full transaction history
Wallet Activity Page
The activity page lists every wallet_transactions row for the customer, including:
- Date and description
- Reference type (ride, topup, manual_bonus, manual_charge, manual_reduce_balance, stripe_charge, etc.)
- Amount (credit in green, debit in red)
- Running
balance_after
Adding Wallet Credits
The dashboard exposes three actions in the customer's Wallet dropdown. All three write to the single wallet_balance and log a wallet_transactions row.
Add Bonus
Promotional or goodwill credit. Increases wallet balance.
- Transaction:
type: 'credit',reference_type: 'manual_bonus' - Notification: none
- API:
POST /api/customers/bonus
{
"customer_uuid": "customer-uuid",
"amount_usd": 5.00
}
Accepted identifier fields (provide at least one): customer_uuid, customer_number, auth_uid, email, or customer_identifier.
Common Reasons to Add Credit
| Reason | Typical Amount |
|---|---|
| Service issue compensation | $5–$20 |
| Technical problem refund | Varies — prefer a ride refund (see below) |
| Goodwill / retention | $5–$10 |
| Promotional campaign | Varies |
Charging Fees & Reducing Balance
Charge Fee
For damages, lost equipment, parking violations, and similar penalties.
- Transaction:
type: 'debit',reference_type: 'manual_charge' - Can go negative: yes
- Notification: push notification sent when balance crosses from positive to negative
- Permission: requires
customer:charge— analysts and service technicians are blocked - API:
POST /api/customers/charge
{
"customer_uuid": "customer-uuid",
"amount_usd": 25.00
}
Reduce Balance
For silent corrections and adjustments that shouldn't notify the customer.
- Transaction:
type: 'debit',reference_type: 'manual_reduce_balance' - Can go negative: yes (same behavior as Charge Fee)
- Notification: never
- Permission: requires
customer:charge - API:
POST /api/customers/reduce-balance
{
"customer_uuid": "customer-uuid",
"amount_usd": 10.00
}
Charge Fee vs. Reduce Balance
| Feature | Charge Fee | Reduce Balance |
|---|---|---|
| Can go negative | Yes | Yes |
| Sends notification | When crossing from positive to negative | Never |
| Typical use | Penalties, damages | Corrections, adjustments |
| Transaction reference_type | manual_charge | manual_reduce_balance |
Refunds: Always Against the Ride
Never credit the wallet directly for a ride issue
A refund is always recorded against the ride record. The wallet credit is a downstream consequence of adjusting the ride — never the starting point. Directly crediting the wallet corrupts net_deposited, partner payouts, and tax remittance.
Use one of these two endpoints depending on the situation:
Fare adjustment — when the ride was overcharged (e.g. customer was billed for time they didn't use):
POST /api/rides/[id]/adjust-fare
{
"newTotalCost": 8.50,
"reason": "Adjusted to reflect actual ride duration"
}
This recalculates tax, adjusts the ride, credits the wallet if the customer overpaid, and updates net_deposited.
Refund — when the fare is correct but the customer deserves money back (bad experience, compensation, etc.):
POST /api/rides/[id]/refunds
{
"destination": "wallet",
"mode": "full",
"reason": "Rider compensation"
}
destination can be wallet or card. mode can be full or partial (with an amount). The API refunds against what was actually paid (card or wallet), records it in ride_refunds, and updates net_deposited.
For goodwill credits not tied to a specific ride, use Add Bonus on the customer detail page.
Bulk Wallet Processing
The Bulk Wallet Processing action on the customer list is not a credit-upload tool. It's a collection tool that charges saved payment methods for customers with negative wallet balances.
- Select customers manually, or use Select All to target everyone currently matching your filters with a negative balance and a Stripe customer on file.
- Click Process — the system attempts to charge each customer's saved payment method for the amount needed to bring the wallet back to zero.
- Results show each customer as
scheduled,skipped,already_exists, orerror.
There is no CSV upload flow for bulk-adding credits today — add them one customer at a time from the dashboard or script the /api/customers/bonus endpoint.
Wallet Transactions
Every change to wallet_balance writes a wallet_transactions row. Transactions have a type (credit or debit) and a reference_type that categorizes the source.
Common reference_type values
| reference_type | Direction | Source |
|---|---|---|
manual_bonus | credit | Dashboard "Add Bonus" |
manual_charge | debit | Dashboard "Charge Fee" |
manual_reduce_balance | debit | Dashboard "Reduce Balance" |
topup | credit | Customer self top-up or auto top-up |
stripe_charge | credit (shown) | Card charge for ride overage |
ride | debit | Wallet portion of a ride payment |
ride_refund | credit | Ride refund to wallet |
The wallet activity UI groups and labels these for operators — the raw values above are what you'll see in the database and in API responses.
Auto Top-up
Auto top-up automatically replenishes a customer's wallet when their balance falls below a threshold, charging their default payment method.
How It Works
- Customer's wallet balance drops below the threshold (typically during a ride-start or ride-payment check).
- System charges the default payment method for the configured top-up amount.
- Wallet is credited.
- Customer receives a push notification confirming the top-up.
Configuration (both must be true)
- Customer setting:
auto_topup_enabledon the customer record — customers opt in during registration (we frame auto top-up as a way to keep the vehicle from being disabled mid-ride; nearly all customers enable it). - Subaccount setting:
auto_topup_enabledon the subaccount, withauto_topup_amount_centsandauto_topup_threshold_cents.
Defaults
| Setting | Default |
|---|---|
| Top-up amount | $15.00 (1500 cents) |
| Threshold | $5.00 (500 cents) |
Example: when a customer's balance drops below $5.00, the system charges $15.00 and credits the wallet.
Safety
- Database locks prevent concurrent auto top-up attempts from double-charging.
- Stripe idempotency keys prevent duplicate charges under network retries.
- Threshold is re-checked after acquiring the lock.
@levyelectric.comaccounts run against Stripe test mode.
Troubleshooting Auto Top-up
- Verify the customer has
auto_topup_enabled. - Verify the subaccount has
auto_topup_enabledand sane amount/threshold values. - Confirm the customer has a valid default payment method.
- Check Stripe for declines.
- Look in
wallet_transactionsfor recenttopupentries.
Reporting
Summary Metrics
The customer list header shows total wallet value and total bonus value across the filtered view.
Auditing Wallet Changes
- Open a customer's Wallet Activity page to see every transaction with timestamps and
balance_after. - Cross-reference
ridedebits against the ride record — the ride'snet_depositedshould reconcile with wallet debit + card charge minus any refunds. - For manual adjustments, the operator's
user.idis recorded asreference_idonmanual_bonus/manual_chargetransactions; the dashboard resolves this to an employee name.
Best Practices
For Operators
- Document every manual adjustment — operator identity is stored, but a reason in the notification/dashboard description helps future audits.
- Use the ride refund flow for ride issues — never compensate ride problems with a direct wallet credit, or partner payouts and tax accounting will be wrong.
- Reserve Add Bonus for promotions and goodwill not tied to a specific ride.
- Restrict permissions — only admin roles and above should have
customer:charge.
For Customer Service
- Check the current balance and recent wallet activity before adding or removing credit.
- When adjusting for a ride issue, open the ride and use Adjust Fare or Refund rather than the wallet dropdown.
- Set expectations with the customer: credits apply automatically on the next ride.
Troubleshooting
Credit not appearing in the customer app
- Confirm the transaction is in the customer's wallet activity.
- Ask the customer to force-close and reopen the app.
- Verify you adjusted the correct customer (check customer_number / email).
Wallet balance looks wrong
- Review recent transactions for unexpected debits or duplicate credits.
- Check ride history for automatic deductions (
reference_type: 'ride'). - If the balance doesn't match the sum of transactions, the
customers.wallet_balancecolumn may be out of sync withwallet_transactions— escalate this.
Customer says their ride refund didn't apply
- Open the ride detail page and check the Refunds section.
- Confirm the refund was processed via
/api/rides/[id]/refundsor/api/rides/[id]/adjust-fare(not a direct wallet credit). - Cross-reference the customer's wallet activity for a matching
ride_refundentry.
Need Help?
For wallet management questions, contact support@levyelectric.com.