FastPrepPayment Ledger with Refunds and Date Queries

Payment Ledger with Refunds and Date Queries

Stripe logoStripe● MediumINTERNONSITE INTERVIEW
Learn

Problem statement

Implement a lightweight payment ledger that records payments, applies full or partial refunds, tracks net revenue, and retrieves recorded payments by date.

Implement processPaymentLedger. Process the operations in order and return one result string for every operation.

Operation format

  • PAYMENT payment_id timestamp amount: record a payment with a unique ID, a strict UTC timestamp in YYYY-MM-DDTHH:mm:ssZ form, and a positive amount. First validate the timestamp, then check whether the ID is already recorded. Return RECORDED on success, INVALID_TIMESTAMP for an invalid timestamp, or DUPLICATE_PAYMENT for a valid-timestamp operation whose ID already exists. A rejected payment has no effect.
  • REFUND payment_id amount: refund a positive amount from an existing payment. Multiple partial refunds are allowed, but their cumulative amount may not exceed the original payment amount. Return REFUNDED, PAYMENT_NOT_FOUND, or INVALID_REFUND. A rejected refund has no effect. A successful full refund does not remove the payment from date-query results.
  • TOTAL: return the current net revenue as a decimal integer. Net revenue is the sum of recorded payment amounts minus successful refunds.
  • PAYMENTS_ON date: return the matching payment IDs as one comma-separated string in original recording order. The date must use strict YYYY-MM-DD form. Return the empty string when no payment matches, or INVALID_DATE when the date is invalid.
  • PAYMENTS_BETWEEN start_date end_date: return payment IDs whose payment date is in the inclusive range, ordered by payment date and then by original recording order within one date. Return the empty string when no payment matches. Return INVALID_RANGE when either date is invalid or start_date is after end_date.

Operation lines are otherwise well-formed. Payment IDs are non-empty and contain no spaces.

Interview follow-ups

The interview report also asked how to optimize date lookup for large data, validate timestamps, query a range such as one month, and persist runtime state in a database. This callable exercise judges the in-memory behavior above; database persistence remains a discussion follow-up.

Function

processPaymentLedger(operations: String[]) → String[]

Examples

Example 1

operations = ["PAYMENT p1 2026-04-10T09:00:00Z 100","PAYMENT p2 2026-04-10T10:30:00Z 70","TOTAL","REFUND p1 30","TOTAL","PAYMENTS_ON 2026-04-10"]return = ["RECORDED","RECORDED","170","REFUNDED","140","p1,p2"]

The two unique payments create revenue of 170. Refunding 30 from p1 reduces it to 140. Both payments were recorded on 2026-04-10, so the date query returns their IDs in recording order.

Example 2

operations = ["PAYMENT pay-7 2026-04-11T12:00:00Z 50","PAYMENT pay-7 2026-04-12T12:00:00Z 90","REFUND pay-7 20","REFUND pay-7 31","REFUND missing 1","TOTAL"]return = ["RECORDED","DUPLICATE_PAYMENT","REFUNDED","INVALID_REFUND","PAYMENT_NOT_FOUND","30"]

The duplicate ID is rejected. The successful partial refund leaves 30 of net revenue. Refunding another 31 would exceed the payment's remaining refundable amount.

Example 3

operations = ["PAYMENT p1 2026-02-30T09:00:00Z 25","PAYMENT p2 2026-04-11T09:00:00Z 40","PAYMENTS_ON 2026-13-01","PAYMENTS_BETWEEN 2026-04-12 2026-04-10","PAYMENTS_BETWEEN 2026-04-09 2026-04-12","TOTAL"]return = ["INVALID_TIMESTAMP","RECORDED","INVALID_DATE","INVALID_RANGE","p2","40"]

February 30 and month 13 are invalid. The reversed range is also invalid. Only p2 is recorded, and it falls inside the final inclusive range.

Constraints

  • 1 <= operations.length <= 100000.
  • Every operation has one of the documented forms and uses single spaces between tokens.
  • Payment IDs are non-empty ASCII strings without spaces or commas.
  • Every payment and refund amount is a positive integer at most 10^12.
  • Net revenue, cumulative refunds, and every intermediate monetary value fit in a signed 64-bit integer.
  • A valid payment timestamp is a real UTC instant written exactly as YYYY-MM-DDTHH:mm:ssZ. Query dates use exact YYYY-MM-DD form.
  • Date-query results must be produced without scanning unrelated payment IDs; preserve recording order among returned IDs.

More Stripe problems

See Stripe hiring insights
public String[] processPaymentLedger(String[] operations) {
}
operations["PAYMENT p1 2026-04-10T09:00:00Z 100","PAYMENT p2 2026-04-10T10:30:00Z 70","TOTAL","REFUND p1 30","TOTAL","PAYMENTS_ON 2026-04-10"]
expected["RECORDED", "RECORDED", "170", "REFUNDED", "140", "p1,p2"]
Checking account…