FastPrepTransaction Fraud Report Part 4 — Smart Fraud Error Reporting

Transaction Fraud Report Part 4 — Smart Fraud Error Reporting

Stripe logoStripe● MediumNEW GRADPHONE SCREEN
Learn

Problem statement

Four-part sequence: This is Part 4 of one progressive transaction-fraud interview exercise. It retains Parts 1–3 and adds prioritized error reporting.

  1. Part 1: Verify Transaction Data Integrity.
  2. Part 2: High-Risk Rule Validation.
  3. Part 3: User Behavior Matching.
  4. Part 4: Smart Fraud Error Reporting (you are here).

Implement the final cumulative behavior: check six CSV fields, apply two high-risk rules, compare behavior with a user baseline, and report prioritized errors.

Input

Each string in transactions is one unquoted CSV row with exactly six comma-separated fields, in this order: transaction_id,user_id,amount,payment_method,country,hour. Trim surrounding whitespace from every field. A field containing only whitespace is empty. Rows are processed in input order, and repeated transaction IDs remain separate rows.

Each row of baselines has six strings: [user_id,usual_country,start_hour,end_hour,min_amount,max_amount]. Every nonempty transaction row has exactly one matching user baseline. Hour and amount intervals are inclusive and do not wrap. Numeric fields on nonempty rows are valid decimal integers.

Review rules

  1. If any transaction field is empty, assign only MISSING_FIELD. Do not run the later levels for that row.
  2. Otherwise, assign AMOUNT_OUT_OF_RANGE when the amount is outside the inclusive global interval [normalMin, normalMax]. Assign BLOCKED_METHOD when the payment method appears in blockedMethods; membership is case-sensitive.
  3. Compare the transaction with its user's baseline on three features: exact country, hour inside the baseline interval, and amount inside the baseline interval. If fewer than two of the three features match, assign BEHAVIOR_MISMATCH. This is the at-least-50% matching threshold for three features.

Report

Return a string table. Its first row is ["transaction_id","status","error_1","error_2"]. Append one four-cell row for every transaction, keeping the original transaction ID as its first cell, including an empty ID when that field is missing.

For each transaction, collect error codes in this priority order: MISSING_FIELD, AMOUNT_OUT_OF_RANGE, BLOCKED_METHOD, BEHAVIOR_MISMATCH. Put only the first two codes in the final two cells, using an empty string for any unused code cell. Use status OK when there is no error; otherwise use SUSPICIOUS. The four-cell rows form an aligned columnar report.

Function

buildFraudReport(transactions: String[], baselines: String[][], normalMin: int, normalMax: int, blockedMethods: String[]) → String[][]

Examples

Example 1

transactions = ["tx1,u1,500,card,US,10","tx2,u1,50,cash,CA,20","tx3,u1,550,card,CA,10","tx4,u1,550,card,CA,20","tx5,u1,,card,US,10"]baselines = [["u1","US","9","17","400","600"]]normalMin = 100normalMax = 1000blockedMethods = ["cash"]return = [["transaction_id","status","error_1","error_2"],["tx1","OK","",""],["tx2","SUSPICIOUS","AMOUNT_OUT_OF_RANGE","BLOCKED_METHOD"],["tx3","OK","",""],["tx4","SUSPICIOUS","BEHAVIOR_MISMATCH",""],["tx5","SUSPICIOUS","MISSING_FIELD",""]]

tx1 passes every check. tx2 violates the global amount rule and blocked-method rule; its behavior also mismatches, but only the first two priority codes are reported. tx3 matches hour and amount, so two of three baseline features pass. tx4 matches only amount. tx5 has an empty amount and stops after integrity validation.

Example 2

transactions = ["edge,u2,100,Card,US,0"," ,u2,100,Card,US,0"]baselines = [["u2","US","0","0","100","100"]]normalMin = 100normalMax = 100blockedMethods = ["card"]return = [["transaction_id","status","error_1","error_2"],["edge","OK","",""],["","SUSPICIOUS","MISSING_FIELD",""]]

The global and baseline interval endpoints are inclusive. Card does not equal blocked method card. The second row's trimmed transaction ID is empty, so no later check runs.

Constraints

  • 1 <= transactions.length <= 10000; every row has exactly six CSV fields and contains no quoted commas.
  • 1 <= baselines.length <= 10000; user IDs are unique across baseline rows.
  • 0 <= normalMin <= normalMax <= 1000000000.
  • Every nonempty transaction amount and baseline amount bound is an integer from 0 through 1000000000.
  • Every nonempty transaction hour and baseline hour bound is an integer from 0 through 23, and each baseline lower bound is at most its upper bound.
  • Every nonempty transaction user ID appears in baselines. All identifiers, country labels, and method labels have at most 100 characters.

More Stripe problems

See Stripe hiring insights
public String[][] buildFraudReport(String[] transactions, String[][] baselines, int normalMin, int normalMax, String[] blockedMethods) {
    // Write your code here
}
transactions["tx1,u1,500,card,US,10","tx2,u1,50,cash,CA,20","tx3,u1,550,card,CA,10","tx4,u1,550,card,CA,20","tx5,u1,,card,US,10"]
baselines[["u1","US","9","17","400","600"]]
normalMin100
normalMax1000
blockedMethods["cash"]
expected[["transaction_id", "status", "error_1", "error_2"], ["tx1", "OK", "", ""], ["tx2", "SUSPICIOUS", "AMOUNT_OUT_OF_RANGE", "BLOCKED_METHOD"], ["tx3", "OK", "", ""], ["tx4", "SUSPICIOUS", "BEHAVIOR_MISMATCH", ""], ["tx5", "SUSPICIOUS", "MISSING_FIELD", ""]]
Checking account…