Idempotent Top-Up API
Problem
We expose a Spring Boot endpoint POST /topups that adds credit to a subscriber's balance. Mobile clients retry on timeouts, so the same top-up sometimes arrives two or three times and the customer gets charged once but credited twice. Design the endpoint so that retries are safe, then implement the core service method in memory: topUp(idempotencyKey, msisdn, amount) returns the resulting balance and must produce exactly one credit per key, even under concurrent calls.
In the Java version I expect to hear about @Transactional, a unique constraint on the idempotency key, and what happens when two threads hit the method at once.
Examples
Example 1
topUp("k1", "0100000001", 50) → balance 50; topUp("k1", "0100000001", 50) again → still 50 (replayed response, no second credit); topUp("k2", "0100000001", 20) → 70.
Example 2
topUp("k9", "0100000002", 30) succeeds; topUp("k9", "0100000002", 99) — same key, different payload → reject with a conflict error rather than silently returning the old result.
Constraints
- Keys are client-generated UUIDs, valid for 24 hours
- Two concurrent requests with the same key must not both credit
- Balance is an integer number of piasters, never negative
What they look for
Store-then-act ordering (insert the key first, credit second, inside one transaction), a DB unique constraint as the real guard, payload hash comparison for the conflict case, and knowing that synchronized does not help across two pods.