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 |
|
Matches Plaid transaction categories and names against known payroll patterns. |
B — Statistical |
|
Analyses transaction date and amount statistics to identify regular payroll cadence. |
C — Name + Amount |
|
Matches transaction names against income patterns and applies mean-amount thresholds. |
D — Gig Income |
|
Matches transaction names against a curated list of known gig-economy income sources. |
ML — SageMaker Model |
|
Invokes the |
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:
-
outcome—found(payroll detected) ornot_found. -
payroll— detected income transactions (empty fornot_found). -
error_code— optional, additive. Present only when anot_foundoutcome was caused by a recoverable failure rather than a genuine absence of payroll. Existing consumers that ignore this field are unaffected. -
low_txns_detected—truewhen 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 theoutcome/error_codefields. When transactions could not be retrieved at all (NO_TRANSACTIONS), this is alwaystrue.
error_code |
Meaning |
|---|---|
(absent) |
Genuine result — either payroll was found, or detection ran cleanly and found none ( |
|
Could not retrieve the user’s transactions from txn-service to run detection. |
|
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.
Related Pages
-
Architecture — System context and Lambda inventory
-
Event Flows — EventBridge event routing and downstream consumers
-
DynamoDB Tables —
income_detectionentity schema -
Feature Flags — Full GrowthBook flag reference