A client sends POST /payments, the response is lost to a timeout, and the client retries. Without protection, you just charged someone twice. The standard fix is an idempotency key: the client attaches a unique key to the request, and the server guarantees that all requests carrying that key produce exactly one side effect.
You are given a gateway object that behaves like a payment processor. It exposes one method:
gateway.charge(amount) # performs the charge, returns {"txn_id": "txn_N"}
Every call to charge moves real money, so calling it twice for one logical request is the bug this problem is about.
Implement PaymentAPI:
__init__(self, gateway) — store the gatewayhandle(self, request: dict) -> dict — process one request. request has an amount (int) and a key (string, or None).Behavior:
key is None → no idempotency. Charge every time, return {"status": 201, "txn_id": <new>}.key is new → charge once, remember the result, return {"status": 201, "txn_id": <new>}.key seen before, same amount → do not charge. Replay the stored transaction: {"status": 200, "txn_id": <original>}.key seen before, different amount → do not charge. Return {"status": 422, "error": "idempotency_key_reuse"}.Example:
handle({"key": "abc", "amount": 100})→{"status": 201, "txn_id": "txn_1"}handle({"key": "abc", "amount": 100})→{"status": 200, "txn_id": "txn_1"}(replayed, gateway untouched)handle({"key": "abc", "amount": 999})→{"status": 422, "error": "idempotency_key_reuse"}
Constraints:
amount is a positive integer; key is a non-empty string or NoneOfficial solution locked
Give the problem a real attempt before peeking — revealing it affects your credit for this problem for 4 hours.