intermediate
customers
wallets
bonuses

Customer Wallets & Bonus Credits

How the customer wallet works, how to add or remove credits, how auto top-up is configured, and how refunds flow through rides

Levy Fleets TeamJanuary 15, 202515 min read

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

1

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.

2

Wallet is debited

For pay-per-ride customers, the wallet is debited for the ride total (including tax and any out-of-zone fees).

3

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

  1. An active subscription or an active ride package with remaining rides/minutes, and
  2. 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

ReasonTypical Amount
Service issue compensation$5–$20
Technical problem refundVaries — prefer a ride refund (see below)
Goodwill / retention$5–$10
Promotional campaignVaries

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

FeatureCharge FeeReduce Balance
Can go negativeYesYes
Sends notificationWhen crossing from positive to negativeNever
Typical usePenalties, damagesCorrections, adjustments
Transaction reference_typemanual_chargemanual_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, or error.

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_typeDirectionSource
manual_bonuscreditDashboard "Add Bonus"
manual_chargedebitDashboard "Charge Fee"
manual_reduce_balancedebitDashboard "Reduce Balance"
topupcreditCustomer self top-up or auto top-up
stripe_chargecredit (shown)Card charge for ride overage
ridedebitWallet portion of a ride payment
ride_refundcreditRide 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

  1. Customer's wallet balance drops below the threshold (typically during a ride-start or ride-payment check).
  2. System charges the default payment method for the configured top-up amount.
  3. Wallet is credited.
  4. Customer receives a push notification confirming the top-up.

Configuration (both must be true)

  • Customer setting: auto_topup_enabled on 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_enabled on the subaccount, with auto_topup_amount_cents and auto_topup_threshold_cents.

Defaults

SettingDefault
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.com accounts run against Stripe test mode.

Troubleshooting Auto Top-up

  1. Verify the customer has auto_topup_enabled.
  2. Verify the subaccount has auto_topup_enabled and sane amount/threshold values.
  3. Confirm the customer has a valid default payment method.
  4. Check Stripe for declines.
  5. Look in wallet_transactions for recent topup entries.

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 ride debits against the ride record — the ride's net_deposited should reconcile with wallet debit + card charge minus any refunds.
  • For manual adjustments, the operator's user.id is recorded as reference_id on manual_bonus / manual_charge transactions; the dashboard resolves this to an employee name.

Best Practices

For Operators

  1. Document every manual adjustment — operator identity is stored, but a reason in the notification/dashboard description helps future audits.
  2. 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.
  3. Reserve Add Bonus for promotions and goodwill not tied to a specific ride.
  4. Restrict permissions — only admin roles and above should have customer:charge.

For Customer Service

  1. Check the current balance and recent wallet activity before adding or removing credit.
  2. When adjusting for a ride issue, open the ride and use Adjust Fare or Refund rather than the wallet dropdown.
  3. 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_balance column may be out of sync with wallet_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]/refunds or /api/rides/[id]/adjust-fare (not a direct wallet credit).
  • Cross-reference the customer's wallet activity for a matching ride_refund entry.

Need Help?

For wallet management questions, contact support@levyelectric.com.