Invoice / Payment Reconciliation
Learn this problemProblem statement
You are reconciling a single incoming payment against a list of open invoices. Decide which invoice the payment settles by applying matching rules in strict priority order, and return a human-readable result string.
Input format (all values are CSV-style strings):
paymenthas the form"payment-id, amount, memo". Thememomay itself contain commas.amountis an integer number of cents.- each invoice has the form
"invoice-id, due-date, amount"wheredue-dateisYYYY-MM-DDandamountis an integer number of cents. forgivenessis a non-negative integer tolerance in cents (it may be0).
Parsing the payment: split payment on the separator ", ". The first field is payment-id, the second is amount, and everything after that, re-joined with ", ", is the memo (so a comma inside the memo does not corrupt it).
Matching rules (apply strictly in this order; the first tier that yields a candidate wins):
- ID match (highest priority): scan the
memocase-insensitively for the markerpaying for:orpaying off:. If present, the invoice id is the text after the marker, trimmed (preserve its original casing). If an invoice has that id, it matches even if the amount disagrees. - Exact amount match: if no id match, match invoices whose
amountequals the paymentamountexactly. - Fuzzy amount match (lowest priority, only when
forgiveness > 0): match invoices whose amount lies within the inclusive range[amount - forgiveness, amount + forgiveness]. A difference exactly equal toforgivenessstill qualifies. Skip any invoice whose amount equals the payment exactly (those belong to the exact tier).
Within whichever tier produces candidates, if more than one invoice qualifies, pick the one with the earliest due-date. Because dates are YYYY-MM-DD, ordinary string comparison orders them correctly.
Output: on a match return "Payment {payment-id} paid {amount} for invoice {invoice-id} due on {date}". If no tier matches, return "Payment {payment-id} could not be matched to any invoice".
Function
reconcilePayment(payment: String, invoices: String[], forgiveness: int) → StringExamples
Example 1
payment = "pay_1, 100, paying for: INV-7"invoices = ["INV-7, 2026-03-01, 250", "INV-3, 2026-02-01, 100"]forgiveness = 0return = "Payment pay_1 paid 100 for invoice INV-7 due on 2026-03-01"Example 2
payment = "pay_2, 100, March rent, thanks"invoices = ["INV-9, 2026-04-01, 100", "INV-4, 2026-01-15, 100"]forgiveness = 0return = "Payment pay_2 paid 100 for invoice INV-4 due on 2026-01-15"Example 3
payment = "pay_3, 98, bank transfer"invoices = ["INV-1, 2026-05-01, 100", "INV-2, 2026-06-01, 130"]forgiveness = 2return = "Payment pay_3 paid 98 for invoice INV-1 due on 2026-05-01"Example 4
payment = "pay_4, 500, no matching invoice here"invoices = ["INV-1, 2026-05-01, 100", "INV-2, 2026-06-01, 130"]forgiveness = 0return = "Payment pay_4 could not be matched to any invoice"Constraints
paymentis formatted as"payment-id, amount, memo"; the memo may contain", "separators and should be re-joined.- Each invoice is formatted as
"invoice-id, due-date, amount"withdue-dateinYYYY-MM-DD. - All amounts are integers (cents).
forgiveness >= 0. - The fuzzy range is inclusive on both ends; a difference exactly equal to
forgivenessqualifies. - Tiers are evaluated strictly in order ID > exact > fuzzy; an earlier tier short-circuits later tiers.
- Within a tier, ties are broken by the earliest
due-dateusing lexicographic string comparison.
More Stripe problems
- Group Linked Merchant RecordsPHONE SCREEN · Seen Jul 2026
- Incident MonitorOA · Seen Jul 2026
- Merchant Fraud Risk ScoringOA · Seen Jul 2026
- WebSocket Load Balancer — Basic Load Balancing (Part 1)OA · Seen Jul 2026
- Rule-Driven Transaction Fraud DetectionOA · PHONE SCREEN · Seen Jul 2026
- Deployment Window SchedulerOA · Seen Jul 2026
- Directly Linked UsersOA · Seen Jun 2026
- Fraud Ring SizeOA · Seen Jun 2026