Match payments to invoices by memo or amount
StripeData Scientist · Technical ScreenLast updated
This question evaluates string parsing, record linkage, and algorithmic matching skills for data reconciliation tasks, including handling messy memo text, exact amount matches, and tie-breaking by earliest due date.
Scenario
You are building a small reconciliation tool that matches payments to invoices.
Data structures
Assume you are given:
-
invoices: a list of invoice objects/records with fields: -
invoice_id: string(unique) -
amount: int(ordecimal; assume exact match is possible) -
due_date: stringin ISO formatYYYY-MM-DD -
payments: a list of payment objects/records with fields: -
payment_id: string(unique) -
amount: int -
memo: string(free-form text; may contain extra spaces)
Memo format
Some payments have a standard memo format that includes an invoice id, e.g.:
"Paying off: INV-12345 ..."
If the memo contains the substring "Paying off:", then the invoice id immediately following it (after trimming spaces) is the target invoice_id. (You may assume the invoice id token ends at the next whitespace.)
Task
Implement matching logic to process each payment and produce a match result.
Part 1 (ID-based)
For payments whose memo contains "Paying off:":
- Parse the invoice id from the memo.
- Find the invoice with that
invoice_id. - Output a record indicating the payment matched that invoice.
- If no such invoice exists, output an error for that payment (e.g.,
"cannot find invoice_id=...").
Part 2 (extended: ID-based OR amount-based)
Extend the logic as follows:
- If the memo contains
"Paying off:", use the ID-based logic from Part 1. - Otherwise, use amount-based matching:
- Find all invoices with
invoice.amount == payment.amount. - If none exist, output an error for that payment (e.g.,
"cannot find matching invoice for amount=..."). - If multiple invoices match by amount, choose the one with the earliest
due_date.
Output requirements
Return a list of match results (one per payment), where each result includes:
payment_idmatched_invoice_id(ornullif unmatched)match_mode: one of{ "id", "amount" }(or"unmatched")- optionally an
error_messagefor unmatched cases
Constraints / edge cases to handle
- Extra spaces in
memoaround"Paying off:"and/or the invoice id token. - Large input sizes: design for near-linear time in the number of invoices + payments.
- Multiple invoices can share the same amount; tie-break using earliest due date.
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.