Rules Reference
This page documents all individual rules available in the Underwriting Engine (located in pkg/rules). Each rule implements specific logic to evaluate a user’s eligibility for Floats or Installment Loans.
Rule Categories
Rules are organized by the dimension they evaluate:
| Category | Purpose | Rule Count |
|---|---|---|
Account Health |
Verify account status and standing |
3 rules |
Transaction Activity |
Analyze account usage patterns |
6 rules |
Payment History |
Evaluate loan repayment behavior |
3 rules |
Income Stability |
Verify regular income and deposits |
3 rules |
Risk Assessment |
Identify fraud and suspicious behavior |
4 rules |
Balance & Limits |
Verify available funds and limits |
3 rules |
Behavior Patterns |
Analyze spending and transfer patterns |
4 rules |
Subscription & Loyalty |
Verify subscription status and renewals |
1 rule |
External Scoring |
Use ML models and external services |
3 rules |
Rules Summary Table
| Rule | Type | Key Properties | Min Float Rank |
|---|---|---|---|
Account |
min_age (days) |
- |
|
Balance |
available_threshold |
- |
|
Balance |
min_balance, max_balance, max_float_rank |
0-N |
|
Balance |
min_available, min_current |
Optional |
|
Scoring |
min_cash_advance_score, loan_amount_window |
Optional |
|
Payment |
max_error_ratio |
- |
|
Activity |
min_advances, min_repayments, number_of_days |
Optional |
|
Activity |
required_float_rank, required_number_of_transactions |
Y |
|
Activity |
required_min_borrow_amount, required_min_repayment_amount |
- |
|
Account |
min_float_rank, max_float_rank |
- |
|
Account |
None |
- |
|
Behavior |
max_transfer_ratio, min_income |
- |
|
Risk |
institution_list, min_balance |
- |
|
Activity |
average_transactions, float_rank |
- |
|
Scoring |
min_prediction_score, max_float_count |
Optional |
|
Scoring |
low_float_threshold, high_float_threshold, min_float_count_for_high_threshold |
- |
|
Risk |
max_accounts |
- |
|
Payment |
days_after_float_on_time, required_last_floats_on_time |
Y |
|
Behavior |
N/A |
- |
|
Payment |
max_days |
Y |
|
Income |
min_income |
- |
|
Income |
min_income, transfer_ratio |
- |
|
Behavior |
spend_percentage, min_income, days_after_income |
- |
|
Loyalty |
min_rank, paid_within_days |
- |
|
Risk |
high_account_balance, min_age_of_account |
- |
|
Behavior |
transfer_categories, max_transfer_percentage |
- |
|
Account |
None |
- |
RuleAgeOfAccount
Establishes that the user’s account has been active for a minimum duration by checking the age of the oldest transaction.
-
Properties:
-
min_age(Integer): The minimum required age in days
-
-
Input Data: User transaction history
-
Pass Criteria: Oldest transaction date is older than
min_agedays ago -
Fail Criteria: Account is younger than
min_agedays -
Use Case: Prevent fraud from newly-created accounts
-
Common Values:
min_age = 30, 60, 90days
Example:
Configuration: min_age = 30 days
User account created: 45 days ago
Result: PASS (45 > 30)
RuleBalanceRequirement
Verifies the user maintains minimum funds in either Available or Current balance, optionally requiring a minimum float history.
-
Properties:
-
min_available(Integer/int64): Minimum required available balance (cents) -
min_current(Integer/int64): Minimum required current balance (cents) -
min_num_of_floats(Integer, Optional): Minimum completed floats required
-
-
Input Data: Account balances, float history
-
Pass Criteria:
-
(If
min_num_of_floatsset) User must have completed that many floats -
AND (Available Balance >=
min_availableOR Current Balance >=min_current)
-
-
Fail Criteria: Both balances below thresholds OR float count insufficient
-
Use Case: Ensure user has capacity to repay
-
Common Values:
min_available = $50-500, min_current = $100-1000
Example:
Configuration:
min_available: 5000 (cents = $50)
min_current: 10000 (cents = $100)
User State:
available_balance: 15000 ($150)
current_balance: 8000 ($80)
Result: PASS
(available_balance $150 >= $50)
RuleGoodStanding
Fundamental account health check ensuring the user is an active customer without outstanding debts.
-
Properties: None
-
Input Data: User status, active floats, pending transactions
-
Pass Criteria:
-
User status is "ACTIVE" (not disabled/suspended)
-
No outstanding (Active/Pending) floats
-
No payment failures
-
-
Fail Criteria: User disabled OR has unpaid float outstanding
-
Use Case: Gating rule - prevents approving inactive or over-indebted users
-
Criticality: Often configured as required gate
Example:
User State:
status: "ACTIVE" ✓
active_floats: [] (empty) ✓
pending_payments: [] (empty) ✓
Result: PASS (all conditions met)
RuleValidDebitCard
Verifies the user has a valid debit card on file for repayment processing.
-
Properties: None
-
Input Data: Debit card information from payment service
-
Pass Criteria:
DebitCard.IsValidis true -
Fail Criteria: No valid debit card
-
Use Case: Ensure repayment mechanism exists
-
Criticality: Gateway rule - cannot approve without payment method
Example:
User State:
debit_card:
card_ending_in: 1234
is_valid: true
expiration: 2026-12-31
Result: PASS
RuleLowTransactions
Ensures the user actively uses their account (minimum transaction velocity).
-
Properties:
-
days_to_consider(Integer): Lookback period in days -
average_transactions(Float): Minimum average transactions per day -
float_rank(Integer): Float count threshold for exemption -
run_chime_varo_check(Boolean): Enable special logic for these institutions
-
-
Input Data: Transaction history, bank institution, float history
-
Pass Criteria:
-
Average txns/day >=
average_transactions -
OR User has >
float_rankcompleted floats AND no active float -
OR (If enabled) Chime/Varo special rules pass
-
-
Fail Criteria: Too few transactions AND no exemption triggered
-
Use Case: Identify dormant accounts (higher risk)
-
Common Values:
average_transactions = 2.0, float_rank = 5
Example:
Configuration:
days_to_consider: 30
average_transactions: 1.5 (1.5 transactions/day)
float_rank: 3
User State:
transactions_last_30_days: 60
average: 2.0 txns/day
float_history: 2 floats
Result: PASS (2.0 >= 1.5)
RuleEssentialSpend
Rewards users who spend on essential categories (groceries, gas, utilities), indicating responsible budgeting.
-
Properties:
-
required_float_rank(Integer): Minimum floats to qualify -
required_dollar_amount(Integer): Minimum transaction amount -
required_number_of_transactions(Integer): Count threshold -
essential_categories(List of Strings): Plaid category list -
days_to_consider(Integer): Lookback period
-
-
Input Data: Categorized transactions (via Plaid)
-
Pass Criteria:
-
User has >=
required_float_rankfloats -
AND >=
required_number_of_transactionsin essential categories -
AND each >=
required_dollar_amount
-
-
Fail Criteria: Thresholds not met
-
Use Case: Approve users with demonstrated financial responsibility
-
Common Values:
required_float_rank = 1, required_number_of_transactions = 3
RuleCompetitorEwa
Analyzes whether user actively uses competitor Early Wage Access (EWA) services, indicating financial need but also experience with loans.
-
Properties:
-
number_of_days(Integer): Lookback window in days -
min_advance_amount(Integer): Threshold to count as cash advance -
min_inflows(Integer): Minimum competitor advances required -
min_repayments(Integer): Minimum competitor repayments required -
min_floats(Integer): Minimum FloatMe floats to apply rule
-
-
Input Data: Transaction history, merchant classification
-
Pass Criteria:
-
User has >=
min_floatsFloatMe floats (or N/A if not set) -
AND >=
min_inflowscompetitor advances -
AND >=
min_repaymentscompetitor repayments
-
-
Fail Criteria: Counts insufficient
-
Use Case: Target users experienced with short-term lending
-
Common Values:
min_inflows = 2, min_repayments = 2, min_floats = 0
Example:
Configuration:
days_to_consider: 90
min_advance_amount: 2500 ($25)
min_inflows: 2
min_repayments: 2
User Transactions (90 days):
Competitor A: +$25 (inflow 1)
Competitor A: +$20 (inflow 2)
Competitor A: -$25 (repayment 1)
Competitor B: -$20 (repayment 2)
Result: PASS (meets all counts)
RuleTransferRatio
Identifies users who primarily transfer money (potentially money laundering or fraudulent activity).
-
Properties:
-
days_to_consider(Integer): Lookback window -
transfer_categories(List of Strings): Merchant categories counting as transfers -
required_number_of_transactions(Integer): Minimum txns to evaluate (avoids false positives) -
max_transfer_percentage(Float): Maximum allowed % transfers
-
-
Input Data: Categorized transactions
-
Pass Criteria:
-
(Transfer Txns / Total Txns) * 100 ⇐ max_transfer_percentage -
OR Too few transactions to evaluate (below
required_number_of_transactions)
-
-
Fail Criteria: Transfer percentage exceeds threshold
-
Use Case: Fraud prevention
-
Common Values:
max_transfer_percentage = 30.0
Example:
Configuration:
max_transfer_percentage: 30%
required_number_of_transactions: 10
User Transactions (30 days): 20 total
Transfer txns: 4
Other txns: 16
Calculation: (4/20) * 100 = 20%
Result: PASS (20% <= 30%)
RuleEWADollarAmount
Similar to CompetitorEwa but evaluates total dollar amounts borrowed and repaid (vs. transaction counts).
-
Properties:
-
days_to_consider(Integer): Lookback window -
required_min_borrow_amount(Integer): Minimum total borrowed -
required_min_repayment_amount(Integer): Minimum total repaid -
min_advance_amount(Integer): Threshold per transaction
-
-
Input Data: Transaction history, merchant classification
-
Pass Criteria: Total Borrowed >= threshold AND Total Repaid >= threshold
-
Fail Criteria: Amounts insufficient
-
Use Case: Identify active, substantial users of competitor services
-
Common Values:
required_min_borrow_amount = 10000 ($100), required_min_repayment_amount = 10000
RuleOnTimeFloatPayback
Validates that the user has a recent pattern of paying floats back on time.
-
Properties:
-
days_after_float_on_time(Integer): Grace period (definition of on-time) -
required_last_floats_on_time(Integer): How many recent floats must be on time -
required_float_rank(Integer): Minimum total floats required
-
-
Input Data: Float history, repayment dates
-
Pass Criteria:
-
User has >=
required_float_rankcompleted floats -
AND last
required_last_floats_on_timeconsecutive floats paid within grace period
-
-
Fail Criteria: Float rank too low OR recent floats have late payments
-
Use Case: Reward reliable borrowers
-
Criticality: Often required for repeat users
-
Common Values:
days_after_float_on_time = 3, required_last_floats_on_time = 3
RuleRecentFloat
Checks that the user actively borrows (paid back a float recently).
-
Properties:
-
max_days(Integer): Maximum days since last payback
-
-
Input Data: Float history, repayment dates
-
Pass Criteria: Most recent float payback is within
max_daysago -
Fail Criteria: Last float was paid back too long ago
-
Use Case: Identify dormant but otherwise qualified users
-
Common Values:
max_days = 180(6 months)
RuleCollectionsErrors
Analyzes payment failure rate (Usio debit collection errors) relative to float volume.
-
Properties:
-
max_error_ratio(Float): Maximum allowed ratio errors:floats
-
-
Input Data: Failed debit transactions, float count
-
Pass Criteria:
(Error Count / Completed Floats) < max_error_ratio -
Fail Criteria: Ratio >= threshold
-
Use Case: Prevent users with payment method issues
-
Common Values:
max_error_ratio = 0.15(max 15% failure rate)
Example:
User State:
failed_debits: 2
completed_floats: 20
Calculation: 2 / 20 = 0.10 (10%)
Configuration: max_error_ratio = 0.15 (15%)
Result: PASS (10% < 15%)
RuleRecurringDeposits
Verifies the user receives regular payroll or income deposits.
-
Properties:
-
min_income(Integer): Minimum amount to count as payroll
-
-
Input Data: Transaction history, income classification
-
Pass Criteria:
-
At least 2 payroll deposits in lookback period
-
AND at least one is "recent" (within typical pay schedule)
-
-
Fail Criteria: Insufficient income instances or no recent income
-
Use Case: Verify income stability
-
Common Values:
min_income = 10000($100)
Example:
User Transaction History (90 days):
Deposits >= $100:
Day 15: $1000 (paycheck) ✓
Day 30: $1000 (paycheck) ✓ recent
Day 60: $500 (other income)
Result: PASS (2 payroll deposits, 1 recent)
RuleRecurringDepositsAndHighTransfer
Combines income stability check with transfer behavior check. User must have recent income AND not immediately transfer it away.
-
Properties:
-
min_income(Integer): Minimum income amount -
transfer_ratio(Float): Max allowed transfer ratio
-
-
Input Data: Income deposits, transfer transactions
-
Pass Criteria:
-
(At least one recent Payroll Income AND No High Transfers found)
-
OR (At least one recent "Any Income" > min AND No High Transfers)
-
-
Fail Criteria: No recent income OR High Transfers detected
-
Use Case: Approve users with stable income and reasonable spending
-
Complexity: Combines two rule logics
RuleSpendVelocity
Identifies users who spend their paycheck too quickly after payday (risky spending pattern).
-
Properties:
-
spend_percentage(Float): Threshold % of income to spend -
min_income(Integer): Minimum income to apply rule -
days_after_income(Integer): Lookback window after payday -
allowed_high_spend_instances(Integer): Max violations allowed
-
-
Input Data: Income deposits, spending transactions
-
Pass Criteria: Number of "high spend" instances ⇐
allowed_high_spend_instances -
Fail Criteria: Too many instances where (Spend % Income) > threshold
-
Use Case: Prevent approving users with poor budget control
-
Common Values:
spend_percentage = 0.8, allowed_high_spend_instances = 1
Example:
Configuration:
spend_percentage: 0.8 (80%)
days_after_income: 7
allowed_high_spend_instances: 1
User Recent Paychecks:
Paycheck 1: $1000
Spending within 7 days: $950 (95% > 80%) ← violation 1
Paycheck 2: $1000
Spending within 7 days: $700 (70% < 80%) ← OK
violations = 1, allowed = 1
Result: PASS (violations == allowed)
RuleSuspiciousHighBalance
Flags new accounts with unusually high balances (potential fraud/money laundering).
-
Properties:
-
high_account_balance(Integer): Balance threshold (cents) -
min_age_of_account(Integer): Age threshold (days)
-
-
Input Data: Current balance, account age, float history
-
Pass Criteria: User is NOT suspicious:
-
Account is old enough (>=
min_age_of_account) -
OR Balance is low enough (<
high_account_balance) -
OR User already has floats (grandfathered/trusted)
-
-
Fail Criteria: Account is young AND Balance is high AND No floats
-
Use Case: AML/fraud prevention
-
Common Values:
high_account_balance = 500000 ($5000), min_age = 30days
Example:
Configuration:
high_account_balance: 500000 ($5000)
min_age_of_account: 30 days
New User Account:
age: 5 days (< 30) ❌
balance: 1000000 ($10,000) (> $5000) ❌
float_history: 0 floats ❌
Result: FAIL (suspicious)
RuleInstitutionCheck
Applies special handling for known problematic banking institutions (Chime, Varo, etc.) that allow overdrafts or have delayed posting.
-
Properties:
-
institution_list(List of Strings): List of Institution IDs/names -
min_balance(Integer/int64): Stricter balance requirement
-
-
Input Data: Bank institution, account balances
-
Pass Criteria:
-
User is NOT in
institution_list(Auto-pass for other banks) -
OR User IS in list AND meets stricter balance check:
-
Available Balance >=
min_balancewhile Current Balance >= 0 -
OR Current Balance >=
min_balancewhile Available Balance >= 0
-
-
-
Fail Criteria: In problematic institution AND fails balance check
-
Use Case: Risk mitigation for unreliable bank data
-
Common Values:
institution_list = ["chime", "varo"], min_balance = 50000($500)
RuleMultipleAccounts
Prevents fraud by detecting users with multiple linked accounts in the system.
-
Properties:
-
max_accounts(Integer): Maximum allowed linked accounts
-
-
Input Data: Linked accounts list (from user service)
-
Pass Criteria:
-
User already has completed floats (grandfathered/trusted)
-
OR unique linked accounts count ⇐
max_accounts
-
-
Fail Criteria: Too many linked accounts AND new user
-
Use Case: Fraud/abuse prevention
-
Common Values:
max_accounts = 2
Example:
Configuration: max_accounts = 2
New User (no floats):
Linked accounts: 5
Result: FAIL (5 > 2, no grandfathering)
Existing User (3 previous floats):
Linked accounts: 5
Result: PASS (grandfathered despite high count)
RuleCashAdvanceScore
Uses an external Cash Advance Score (CAS) plus optional float rank constraints to evaluate creditworthiness.
-
Properties:
-
min_cash_advance_score(Integer): Minimum passing CAS -
loan_amount_window(Integer): Loan amount to select correct score interval -
min_float_rank(Integer, Optional): Minimum float count -
max_float_rank(Integer, Optional): Maximum float count -
deny_for_float_rank(Boolean): Enforce float rank range
-
-
Input Data: External CAS service, float history
-
Pass Criteria:
-
Float rank within acceptable bounds (or ignored if not enforced)
-
AND CAS Score >=
min_cash_advance_score
-
-
Fail Criteria: Float rank violated (if enforced) OR CAS Score too low
-
Use Case: Incorporate external lending criteria
-
Complexity: References external scoring system
RuleHighTransfer
Checks for excessive transfers immediately after payday (potential emergency need or financial distress).
-
Properties:
-
max_transfer_ratio(Float): Max allowed (Transfers / Income) ratio -
min_income(Integer): Minimum income to apply
-
-
Input Data: Income deposits, transfer transactions
-
Pass Criteria: No instances where
(Transfers on Payday + Next Day) > (Income * max_transfer_ratio) -
Fail Criteria: One or more "high transfer" instances found
-
Use Case: Identify users in financial distress
-
Common Values:
max_transfer_ratio = 0.5
Example:
Configuration: max_transfer_ratio = 0.5 (50%)
Payday: $2000 deposit
Transfers on Payday + Next Day: $1200
Check: $1200 > ($2000 * 0.5 = $1000) ✓ HIGH TRANSFER
Result: FAIL (found high transfer instance)
RulePayrollSpend
Analyzes spending behavior relative to payday patterns (variant of SpendVelocity).
-
Properties: (Varies, implementation-specific)
-
Input Data: Payroll deposits, spending transactions
-
Use Case: Assess budget control
-
Similar To: SpendVelocity but may have different thresholds
RuleBalanceBetweenBounds
Denies specific balance ranges for new users (prevents "testing" with small amounts).
-
Properties:
-
max_float_rank(Integer): Float count threshold, users below are subject to check -
min_balance(Integer/int64): Lower bound of deny range -
max_balance(Integer/int64): Upper bound of deny range
-
-
Input Data: Current available balance, float history
-
Pass Criteria:
-
User has >=
max_float_rankfloats (experienced users exempt) -
OR Balance is outside deny range:
ABS(AvailableBalance) < min_balance OR ABS(AvailableBalance) > max_balance
-
-
Fail Criteria: New user (< floats) AND balance falls in deny range
-
Use Case: Prevent "testing" accounts, fraud
-
Common Values:
max_float_rank = 1, min_balance = 1000, max_balance = 5000
Example:
Configuration:
max_float_rank: 1
min_balance: 1000 ($10)
max_balance: 5000 ($50)
New User (0 floats):
available_balance: 2500 ($25)
Check: In deny range [1000, 5000]? YES ❌
Result: FAIL (new user with suspicious balance)
RuleAverageBalance
Verifies the user maintains sufficient average available balance over time (financial stability).
-
Properties:
-
available_threshold(Integer/int64): Minimum average available balance required (cents)
-
-
Input Data: Account balance history
-
Pass Criteria: Average Available Balance >=
available_threshold -
Fail Criteria: Average balance below threshold
-
Use Case: Ensure financial stability
-
Common Values:
available_threshold = 50000($500)
Example:
Configuration: available_threshold = 50000 ($500)
User Balance History (30 days):
Day 1: 60000
Day 10: 45000
Day 20: 55000
Day 30: 50000
Average: (60000 + 45000 + 55000 + 50000) / 4 = 52500
Result: PASS (52500 >= 50000)
RuleSubscriptionRank
Uses subscription history and renewals as a proxy for user stability and loyalty to FloatMe.
-
Properties:
-
min_rank(Integer): Minimum subscription renewals required -
paid_within_days(Integer): Subscription must be paid within this many days
-
-
Input Data: Subscription payment history
-
Pass Criteria:
-
Current subscription rank >=
min_rank -
AND (if applicable) subscription payment occurred within
paid_within_days
-
-
Fail Criteria: Rank too low or no recent payment
-
Use Case: Reward loyal subscribers
-
Common Values:
min_rank = 2, paid_within_days = 365
RuleMLPaybackPrediction
Uses a Machine Learning model’s "Probability to Default" prediction score.
-
Properties:
-
min_prediction_score(Float): Maximum allowed probability to default (threshold) -
max_float_count(Integer, Optional): Max float count to apply rule -
deny_non_applicable(Boolean, Optional): Behavior if float count exceeded
-
-
Input Data: ML model inference from Sagemaker
-
Pass Criteria:
-
(If
max_float_countset) Float count ⇐ threshold (or ignored ifdeny_non_applicable = false) -
AND Probability to default ⇐
min_prediction_score
-
-
Fail Criteria: Probability to default > threshold OR float count exceeded with deny flag
-
Use Case: Leverage ML for credit decisions
-
Common Values:
min_prediction_score = 0.3(30% max default probability)
Note: The field is named min_prediction_score but actually represents the maximum allowed bad probability (confusing naming).
RuleMLPaybackPredictionVariableThreshold
Uses a Machine Learning model’s "Probability to Default" prediction score with variable thresholds based on the user’s completed float history.
-
Properties:
-
low_float_threshold(Float): Maximum allowed probability to default for users with fewer completed floats -
high_float_threshold(Float): Maximum allowed probability to default for users with more completed floats -
min_float_count_for_high_threshold(Integer): Minimum completed floats to use the higher (more lenient) threshold
-
-
Input Data: ML model inference from Sagemaker, user’s float history
-
Pass Criteria:
-
If completed floats <
min_float_count_for_high_threshold: Probability to default ⇐low_float_threshold -
If completed floats >=
min_float_count_for_high_threshold: Probability to default ⇐high_float_threshold
-
-
Fail Criteria: Probability to default exceeds the applicable threshold
-
Use Case: Apply stricter ML thresholds to newer users while being more lenient with users who have a proven repayment history
-
Common Values:
low_float_threshold = 0.8, high_float_threshold = 0.85, min_float_count_for_high_threshold = 3
Note: Only floats with COMPLETED debit status are counted when determining which threshold to apply.
Example:
Configuration: low_float_threshold = 0.8, high_float_threshold = 0.85, min_float_count_for_high_threshold = 3
User A: 2 completed floats, score = 0.82 → FAIL (0.82 > 0.8)
User B: 3 completed floats, score = 0.82 → PASS (0.82 <= 0.85)
Rule Execution Order
Within a rulebook, rules are typically executed in order defined in the YAML configuration. There’s no automatic re-ordering based on rule type or dependency. If rule B depends on data from rule A, they should be ordered accordingly in the rulebook definition.
Error Handling
-
If a rule errors (exception): Error is recorded at rule outcome level
-
The rulebook continues to next rule
-
Error is surfaced to rulebook level
-
Rulebook results in ERROR status
-
Final evaluation may return EVALERR status
Custom Properties
Each rule accepts a properties object in YAML that defines its behavior. Properties are rule-specific and type-safe (validated during rulebook loading).