Unit 1 — exactly-once charges under retries and concurrency
PaymentIntent & Idempotency
A customer taps Pay on a checkout page. The phone is on hotel Wi-Fi, the request times out, and the app does what every well-behaved client does: it retries. Behind the scenes that single tap can become three identical POST /charge calls hitting your API within a few hundred milliseconds. If your payment service is naive, the customer is now charged three times for one coffee — and you have a support ticket, a chargeback, and a trust problem.
This unit builds the primitive that makes that impossible: a PaymentIntent with an idempotency key, the contract that lets a client retry freely while the money moves exactly once.
Sub-unit 1 of 7
The product problem
A payments API has one job that it absolutely cannot get wrong: move money the right number of times. Networks drop packets, clients retry, load balancers replay requests, and users double-click. The API must turn that chaos into a single, well-defined outcome per intent.
Functional
- Charge a card for a given amount and currency and return the outcome.
- Let clients safely retry any request without creating duplicate charges.
- Expose the current state of a charge (created, processing, succeeded, failed).
- Support strong-customer-authentication (3-D Secure) step-ups mid-flight.
Non-functional
- Exactly-once semantics for money movement, even under concurrent retries.
- p99 API latency under 200 ms.
- 99.999% availability — payments cannot have a maintenance window.
- Auditable: every state transition is durably recorded.
Constraints
- Clients are untrusted and may retry arbitrarily.
- The card network call is slow (100–800 ms) and itself non-idempotent.
- A charge may be in flight on multiple app servers at once.
The thread running through every requirement is idempotency: the property that doing something twice has the same effect as doing it once. Get this right and retries become free; get it wrong and every network blip is a financial incident.
