Problem · String

Invoice / Payment Reconciliation

Learn this problem
MediumStripe logoStripeFULLTIMEPHONE SCREEN
See Stripe hiring insights

Problem 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):

  • payment has the form "payment-id, amount, memo". The memo may itself contain commas. amount is an integer number of cents.
  • each invoice has the form "invoice-id, due-date, amount" where due-date is YYYY-MM-DD and amount is an integer number of cents.
  • forgiveness is a non-negative integer tolerance in cents (it may be 0).

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):

  1. ID match (highest priority): scan the memo case-insensitively for the marker paying for: or paying 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.
  2. Exact amount match: if no id match, match invoices whose amount equals the payment amount exactly.
  3. 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 to forgiveness still 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) → String

Examples

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"
The memo contains the marker 'paying for:' followed by INV-7, so the ID tier wins immediately. The ID match settles INV-7 even though its amount (250) does not equal the payment amount (100).

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"
There is no marker in the memo, so the ID tier is skipped. Both invoices match the amount exactly (100). The tie is broken by earliest due-date, so INV-4 (2026-01-15) wins over INV-9 (2026-04-01). Note the memo contained a comma and was parsed as a single memo field.

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"
No marker and no exact-amount invoice (none equal 98). With forgiveness = 2, INV-1 qualifies because its amount 100 is within [96, 100]; the difference is exactly 2, which is inclusive. INV-2 (130) is outside the range. INV-1 wins.

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"
No marker, no exact-amount match, and forgiveness is 0 so the fuzzy tier never runs. Nothing matches, so the unmatched message is returned.

Constraints

  • payment is 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" with due-date in YYYY-MM-DD.
  • All amounts are integers (cents). forgiveness >= 0.
  • The fuzzy range is inclusive on both ends; a difference exactly equal to forgiveness qualifies.
  • 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-date using lexicographic string comparison.

More Stripe problems

drafts saved locally
public String reconcilePayment(String payment, String[] invoices, int forgiveness) {
  // write your code here
}
payment"pay_1, 100, paying for: INV-7"
invoices["INV-7, 2026-03-01, 250", "INV-3, 2026-02-01, 100"]
forgiveness0
expected"Payment pay_1 paid 100 for invoice INV-7 due on 2026-03-01"
checking account