Income Detection

Income detection is an on-demand ML classification flow: the API Lambda’s POST /{user_id}/insights/employment/detect endpoint runs a user’s recent Plaid transactions through five detection methods (including a SageMaker ML model) and returns structured income source candidates. It is used during the onboarding employment-detection flow.

A real-time stream signal (the income-signaller Lambda, which emitted income_txn EventBridge events from the FloatMe transaction Kinesis stream, and its downstream funds-notifier consumer) has been removed from the service.

ML-Based Income Detection (API Lambda)

Endpoint: POST /{user_id}/insights/employment/detect
Lambda: prod-insight-api

This endpoint runs a user’s recent Plaid transactions through five detection methods to identify likely income sources. It is used during the employment onboarding flow to pre-populate employer and income data.

Detection Methods

Method Key Description

A — Name + Category

name_and_cat

Matches Plaid transaction categories and names against known payroll patterns.

B — Statistical

stats

Analyses transaction date and amount statistics to identify regular payroll cadence.

C — Name + Amount

name_and_amt

Matches transaction names against income patterns and applies mean-amount thresholds.

D — Gig Income

gig

Matches transaction names against a curated list of known gig-economy income sources.

ML — SageMaker Model

ml

Invokes the income-detection-endpoint SageMaker endpoint with a structured request; returns per-transaction income probability scores.

The response returned to callers is the merged output of Methods C and D (always included). Methods A and B are logged for analysis but are not returned on their own — they are merged into the result only when C and D produce matches (A first, then B if A is empty). The ML method is gated by insight.income_detection.ml.enabled; when enabled, insight.income_detection.ml.percent controls the rollout percentage of users for whom ML results are also merged in. The merge logic is implemented in pkg/employment/detector.go (Detector.Detect).

Response Outcomes

POST /{user_id}/insights/employment/detect always responds with HTTP 200 — failures are expressed in the body via the outcome field rather than an error status. The body carries:

  • outcomefound (payroll detected) or not_found.

  • payroll — detected income transactions (empty for not_found).

  • error_codeoptional, additive. Present only when a not_found outcome was caused by a recoverable failure rather than a genuine absence of payroll. Existing consumers that ignore this field are unaffected.

  • low_txns_detectedtrue when the user’s transaction history contains fewer than 5 unique days with transactions. This flags accounts with too little activity for detection to be reliable (e.g. a newly connected or low-usage bank account), independent of the outcome/error_code fields. When transactions could not be retrieved at all (NO_TRANSACTIONS), this is always true.

error_code Meaning

(absent)

Genuine result — either payroll was found, or detection ran cleanly and found none (employment.ErrNoPayrollFound).

NO_TRANSACTIONS

Could not retrieve the user’s transactions from txn-service to run detection.

DETECTION_FAILED

The detector returned an unexpected error.

SageMaker Integration

The income-detection-endpoint SageMaker endpoint receives a structured IncomeDetectionMLRequest and returns an IncomeDetectionMLReponse containing:

  • PredictionID — unique ID for the inference run

  • Predictions — per-transaction income/non-income label

  • Probabilities — per-transaction income probability score

All five method results plus the ML metadata (prediction ID, probabilities, whether ML was enabled and used) are written to the prod-insight-income-detection DynamoDB table for offline analysis regardless of which method’s results are returned to the caller.

GrowthBook Flags

Flag Key Default Effect

insight.income_detection.ml.enabled

false

Enables invocation of the SageMaker ML endpoint during detection

insight.income_detection.ml.percent

0

Percentage of users (0–100) for whom ML results are returned instead of legacy method results when ML is enabled