Fraud Detection

The Float Service runs a series of fraud checks during float creation. Checks are controlled by configuration and GrowthBook feature flags, allowing individual checks to be toggled or bypassed without a code deployment.

Float Creation Fraud Checks

Fraud checks run as part of POST /{user_id}/floats after subscription validation and before underwriting. If any enabled check fails, the float is rejected. The results are always saved back to the Payments Service after the attempt, regardless of whether the float was approved or denied.

Check Sequence

Float creation request received
        │
        ▼
1. Check App Version
   Minimum build version met? ──No──► ErrAppVersionInvalid ──► reject float
        │ Yes
        ▼
2. Check Float Amount
   Amount within allowed maximum? ──No──► ErrFloatAmount ──► reject float
        │ Yes
        ▼
3. Check Recent Floats (queries RDS)
   Float taken in last 24 hours? ──Yes──► ErrRecentFloat ──► reject float
   Outstanding float exists? ──────Yes──► ErrOutstandingFloat ──► reject float
        │ No
        ▼
4. Check Active Installment Loans (LOC Service)
   OPEN or DEFAULTED loan exists? ──Yes──► ErrOutstandingLoan ──► reject float
        │ No
        ▼
5. Payments Service Fraud Check (external)
   Check fails? ──Yes──────────────────────► reject float
   Connectivity error? ──Yes──────────────► ErrConnectivity ──► reject float
        │ Pass
        ▼
Float creation proceeds (underwriting, disbursement, etc.)
        │
        ▼
Save fraud check results to Payments Service
  (skipped if user is bypassed or Payments check had a connectivity error)

Each check is independently enabled. A check that is disabled is skipped and treated as passed.

Checks Reference

Check What it validates External call

App Version

The requesting app’s build version meets a configured minimum.

None — validated against a configured value.

Float Amount

The requested amount does not exceed the configured maximum.

None — validated against a configured value.

Recent Floats

No float was taken in the last 24 hours and no outstanding float exists for the user.

RDS — queries the floats table directly.

Active Installment Loans

No OPEN or DEFAULTED installment loans exist for the user.

LOC Service — ListLoansForUser()

Payments Service

External fraud check using user context: account ID, float type, install ID, user ID, zip code.

Payments Service — FloatFraudCheck()

Bypass

Users with an active requirements bypass record (see Bypass & Payback) have the Bypassed flag set to true when fraud checks are invoked. In bypass mode, the underwriting eligibility check is skipped entirely. Individual fraud checks may still run (depending on configuration), but the Bypassed flag is passed to the Payments Service fraud check, which may apply different rules for bypassed users.

Fraud check results are not saved back to the Payments Service for bypassed users.

GrowthBook Feature Flags

Flag Effect

floats.collections.max_ach_attempts

Maximum number of automated ACH attempts before a float is defaulted. Default: 3.

floats.collections.max_attempts_on_day

Maximum total collection attempts per day for the webhook balance worker. Default: 3.