Spending Controls
Spending controls let you restrict how, when, and how much customers can spend from their wallet balances, including per-transaction limits, velocity caps, authentication requirements, and role-based rules that apply automatically without customer action.
Overview
Wallet balances represent real liability on your books. Spending controls give you guardrails to limit exposure, satisfy compliance requirements, and prevent abuse without removing the convenience customers expect from a prepaid wallet.
Controls operate at several layers:
- Spending limits, cap the maximum wallet amount applied to a single order
- Velocity caps, restrict total wallet spend over a rolling time window
- Step-up authentication, require email or TOTP verification before large redemptions go through
- KYC gating, block redemption until a customer completes identity verification
- Role-based rules, apply different limits per WooCommerce customer role
All controls are enforced server-side on the atomic debit path. A control failure prevents the debit from posting; the order does not go through on wallet funds until the constraint is satisfied or the customer uses an alternative payment method.
How It Works
When a customer applies wallet funds at checkout, WalletPro evaluates controls in the following sequence before committing the debit:
- Role lookup, identifies the customer's WooCommerce role and loads the matching rule set
- KYC check, if KYC gating is enabled for the role, confirms the customer's verification status
- Spending limit check, verifies the requested redemption amount does not exceed the per-order cap
- Velocity check, sums wallet debits over the configured window and checks against the rolling cap
- Step-up trigger, if the amount meets or exceeds the step-up threshold, a challenge is issued before the debit posts
- Atomic debit, if all checks pass, the balance is debited in a single database transaction with an HMAC-chained audit entry
Checks 2 to 5 happen within the same request. Failure at any step returns a descriptive error to the checkout UI; the balance is never touched.
Velocity caps use a rolling window, not a calendar period. A 24-hour cap set at midnight does not reset at midnight the next day, it always looks back exactly 24 hours from the current moment.
Configuration
All spending control settings are found at WooCommerce > WalletPro > Spending Controls.
Global Defaults
Global defaults apply to all customers who are not covered by a more specific role-based rule. Configure them in the Global Defaults tab.
| Setting | Type | Default | Description |
|---|---|---|---|
| Maximum wallet redemption per order | Currency amount | Unlimited | The most wallet credit a customer can apply to a single order. Leave blank for no limit. |
| Velocity window | Hours (integer) | N/A | The rolling look-back period for velocity enforcement. Leave blank to disable velocity caps. |
| Maximum wallet spend per window | Currency amount | N/A | Total wallet debits allowed within the velocity window. Requires Velocity window to be set. |
| Step-up authentication threshold | Currency amount | N/A | Redemptions at or above this amount trigger a verification challenge. Leave blank to disable step-up. |
| Step-up method | Select | Email OTP | Verification method for step-up: Email OTP or TOTP (authenticator app). |
| Require KYC before redemption | Toggle | Off | Blocks all wallet redemptions until the customer has completed identity verification. |
Role-Based Rules
Role-based rules let you override global defaults for specific WooCommerce customer roles. Open the Role Rules tab under WooCommerce > WalletPro > Spending Controls.
Each rule targets one role and supports all of the same fields as global defaults. When a customer belongs to multiple roles, the rule for the highest-priority role (listed first in the rule table) takes precedence.
| Field | Notes |
|---|---|
| Role | Any registered WooCommerce or WordPress role. Built-in options include Customer, Subscriber, and any custom roles you have created. |
| Maximum wallet redemption per order | Overrides global default for this role. Leave blank to inherit global. |
| Velocity window (hours) | Overrides global default for this role. |
| Maximum wallet spend per window | Overrides global default for this role. |
| Step-up threshold | Overrides global default for this role. |
| Require KYC | Can be enabled per-role even if disabled globally. |
A common pattern is to set conservative global defaults for unverified Customer role accounts, then create a rule for a Verified Customer role with higher or no limits. Promote customers to the verified role automatically using a third-party KYC plugin, or manually through WooCommerce > Customers.
Setting Up Spending Controls: Step by Step
1. Configure global defaults
- Go to WooCommerce > WalletPro > Spending Controls.
- Under the Global Defaults tab, enter a value for Maximum wallet redemption per order if you want a per-order cap. For example,
100.00to cap redemptions at $100 per order. - To enable velocity caps, set Velocity window to a number of hours (e.g.,
24) and set Maximum wallet spend per window to the rolling limit (e.g.,500.00). - To enable step-up authentication, set Step-up authentication threshold (e.g.,
75.00) and choose a Step-up method. - Click Save changes.
2. Add role-based rules (optional)
- Click the Role Rules tab.
- Click Add Rule.
- Select the target Role from the dropdown.
- Fill in only the fields you want to override. Leave others blank to inherit global defaults.
- Click Save Rule. Repeat for additional roles.
- Drag rules into priority order using the handle on the left of each row. The topmost matching rule wins.
3. Configure step-up email template (Email OTP only)
If you use Email OTP as the step-up method, the verification email is sent via WooCommerce's transactional email system. To customise the template:
- Go to WooCommerce > Settings > Emails.
- Find WalletPro: Step-Up Verification and click Manage.
- Edit the subject, heading, and body as needed. The
{otp_code}placeholder inserts the one-time code. - Click Save changes.
4. Test a control
- Create a test customer account with a funded wallet balance.
- Place a test order that would trigger the control you configured (e.g., apply wallet funds above the per-order cap).
- Confirm that checkout rejects or challenges the redemption as expected.
- Review the result in WooCommerce > WalletPro > Audit Log, a
DEBIT_BLOCKEDorSTEPUP_TRIGGEREDentry should appear with the reason and customer ID.
Customer Experience
Customers are not shown the raw control configuration, but they receive clear, actionable messages when a control prevents or gates a redemption.
Spending limit exceeded
If the customer enters a wallet amount above the per-order cap, the checkout input is clamped automatically to the allowed maximum and an inline notice explains the limit:
"Your wallet redemption has been limited to $100.00 for this order. You can pay the remaining balance with another payment method."
Velocity cap reached
If the customer has exhausted their rolling velocity allowance, the wallet payment option is temporarily disabled at checkout with a notice:
"You have reached your wallet spending limit for the current period. Wallet payments will be available again in approximately 6 hours."
The remaining wait time shown is derived from the earliest debit within the velocity window rolling out of scope.
Step-up authentication
When a redemption triggers step-up, a modal or inline challenge appears before the order is submitted:
- The customer sees a prompt explaining that a verification code is required for redemptions above the threshold.
- For Email OTP: a code is sent to their account email. The customer enters the code in the provided field and clicks Verify. Codes expire after 10 minutes.
- For TOTP: the customer opens their authenticator app and enters the current code.
- On successful verification, the checkout proceeds and the debit posts normally.
- Three consecutive failed attempts temporarily lock wallet redemption for the session.
KYC gating
If KYC is required and the customer has not completed verification, a notice appears in the wallet section of checkout and on their My Account > Wallet dashboard:
"Identity verification is required before you can use wallet funds. Complete verification in your account settings."
A link directs them to the KYC flow. The wallet continues to accept top-ups during this time; only redemption is blocked.
Step-up and KYC gating do not apply to merchant-initiated manual credits or debits made from the WooCommerce admin. Controls apply exclusively to customer-initiated redemptions at checkout.
Audit Log Entries
Every control decision is recorded in the tamper-evident audit ledger at WooCommerce > WalletPro > Audit Log. Relevant event types for spending controls:
| Event type | Meaning |
|---|---|
DEBIT_BLOCKED_LIMIT |
Redemption refused because the amount exceeded the per-order spending limit. |
DEBIT_BLOCKED_VELOCITY |
Redemption refused because the customer's velocity cap was exhausted. |
DEBIT_BLOCKED_KYC |
Redemption refused because the customer has not completed KYC. |
STEPUP_TRIGGERED |
Step-up challenge issued. Debit is pending verification. |
STEPUP_PASSED |
Customer passed step-up; debit proceeded. |
STEPUP_FAILED |
Customer failed step-up verification (wrong code or timeout). |
STEPUP_LOCKED |
Session locked after three consecutive step-up failures. |
Each entry records the customer ID, order context, control that triggered, rule set evaluated (global or role-specific), timestamp, and HMAC chain value. Entries cannot be deleted through the UI.
Applying Controls via Filter (Developers)
If the admin UI rules are insufficient, you can override or supplement controls programmatically using the walletpro_spending_controls filter. The filter receives the resolved control set for a customer and can return a modified array.
/**
* Example: raise the velocity cap for customers who joined more than 90 days ago.
*
* @param array $controls Resolved control set for this customer.
* @param int $user_id WP user ID.
* @param WC_Order $order Current order being processed.
* @return array
*/
add_filter( 'walletpro_spending_controls', function( $controls, $user_id, $order ) {
$user = get_userdata( $user_id );
$days_since_registration = ( time() - strtotime( $user->user_registered ) ) / DAY_IN_SECONDS;
if ( $days_since_registration >= 90 ) {
// Double the velocity cap for long-standing customers.
$controls['velocity_cap'] = $controls['velocity_cap'] * 2;
}
return $controls;
}, 10, 3 );
The $controls array keys are:
| Key | Type | Description |
|---|---|---|
order_limit |
float|null |
Maximum wallet amount per order. null means unlimited. |
velocity_window_hours |
int|null |
Rolling window in hours. null disables velocity enforcement. |
velocity_cap |
float|null |
Maximum spend within the velocity window. null disables velocity enforcement. |
stepup_threshold |
float|null |
Step-up trigger amount. null disables step-up. |
stepup_method |
string |
email_otp or totp. |
require_kyc |
bool |
Whether KYC must be completed before redemption. |
See Hooks & Filters for the full filter reference, including additional hooks for step-up outcomes and KYC status checks.
Checking a Customer's Current Control Status (WP-CLI)
You can inspect the resolved controls for any customer without placing a test order:
# Show resolved spending controls for user ID 42
wp wallet controls 42
Output:
User ID: 42
Role rule applied: verified_customer
Order limit: $500.00
Velocity window: 24h
Velocity cap: $1000.00
Velocity used: $220.00
Velocity remaining:$780.00
Step-up threshold: $200.00
Step-up method: email_otp
KYC required: no
KYC status: n/a
The velocity used and velocity remaining values reflect the rolling window at the exact moment the command runs.