Asynchronous Payment Event Processing
Learn this problemProblem statement
Stripe processes asynchronous payment events. Build a small-scale processor that receives events, parses them, and aggregates the latest state and totals for every payment.
Complete processEvents. The events array is given in received order. Each event is a comma-separated string with these seven fields:
event_id,event_time,event_type,payment_id,payment_event_type,merchant_id,amountA missing field is written as -. This Part 1 exercise contains only payment events and the following payment event types:
create: the payment does not exist yet. Create it for the suppliedmerchant_id, initialize both accumulated amounts to0, and set its state tocreated. Theamountfield is-.authorize: the payment is currentlycreatedorauthorized. Addamounttoamount_authorizedand set the state toauthorized. Themerchant_idfield is-.capture: the payment is currentlyauthorizedorpartially_captured. Addamounttoamount_captured. Themerchant_idfield is-.
After a capture, the payment is partially_captured when amount_captured < amount_authorized, and it is successful when the two amounts are equal.
Event IDs are globally idempotent. Process only the first received event with a given event_id; ignore every later row with that ID without changing any payment or timestamp.
For every accepted event, set the payment's last_event_at to that event's event_time. A payment is attached to exactly one merchant.
Output
Return one string per payment, in the order that each payment's accepted create event was processed. Use this exact field order:
payment_id,merchant_id,state,amount_authorized,amount_captured,last_event_atNumeric totals start at 0. Output missing text fields as an empty field rather than -.
Function
processEvents(events: String[]) → String[]Examples
Example 1
events = ["evt1,10,payment,p1,create,m1,-","evt2,20,payment,p1,authorize,-,100","evt3,30,payment,p1,capture,-,40","evt4,40,payment,p1,capture,-,60"]return = ["p1,m1,successful,100,100,40"]The payment moves from created to authorized, then to partially_captured, and finally to successful. Its latest accepted event time is 40.
Example 2
events = ["c1,1,payment,pA,create,shopA,-","a1,2,payment,pA,authorize,-,80","c2,3,payment,pB,create,shopB,-","a1,4,payment,pA,authorize,-,80","a2,5,payment,pA,authorize,-,20","b1,6,payment,pB,authorize,-,50"]return = ["pA,shopA,authorized,100,0,5","pB,shopB,authorized,50,0,6"]The second row with event ID a1 is ignored globally, so it does not add another 80 or change the last event time. Results follow payment creation order.
Example 3
events = ["e1,7,payment,p1,create,m1,-","e2,8,payment,p2,create,m2,-","e3,9,payment,p2,authorize,-,120","e4,10,payment,p2,capture,-,20"]return = ["p1,m1,created,0,0,7","p2,m2,partially_captured,120,20,10"]Payment p1 has only a creation event, so both numeric totals remain 0. Payment p2 has captured less than its authorized amount.
Constraints
1 <= events.length <= 10^5.- Every event contains exactly seven comma-separated fields, and no field contains a comma.
- Every non-missing identifier is non-empty and contains only letters, digits, underscores, or hyphens.
0 <= event_time <= 10^9.- Every
authorizeorcaptureamount is in[1, 10^9], and every accumulated amount fits in a signed 64-bit integer. - Except for repeated event IDs, events follow the valid transition table in received order, and a capture never makes
amount_capturedexceedamount_authorized.