Hi, Aniket here 👋🏻 and welcome to my System Design Newsletter 😊!
The accuracy and reliability of transactions are paramount in a payment system. One of the most critical issues that can arise is double charging a customer for a single transaction. Avoiding double payments is essential not only to maintain customer trust and satisfaction but also to prevent financial losses and potential legal issues for businesses.
While designing the payment system, it is important to guarantee that the payment system executes an order exactly once. This can be achieved if following conditions are satisfied:
Payment is executed at least once - Using RETRY
Payment is executed at most once - Through IDEMPOTENCY
RETRY
Occasionally, we need to retry a payment transaction due to network errors or timeout. Retry provides the at-least-once guarantee.
For example, as shown in Figure 1, the client tries to make a $10 payment, but the payment keeps failing due to a poor network connection.
Considering the network condition might get better, the client retries the request and this payment finally succeeds at the fourth attempt.
IDEMPOTENCY
From an API standpoint, idempotency means clients can make the same call repeatedly and produce the same result.
Second part of Figure 1 presents a scenario where customer pressed pay button multiple times but system charges customer only once. Here’s how:
Client sends a unique key (itempotency_key) along with every request.
After initiating the transaction with the payment provider, itempotency_key is persisted in cache.
Since customer pressed the pay button twice, client makes API call with the same itempotency_key again.
Since this key already exists in cache, so previous success response is returned instead of initiating the payment again.
Few characteristics of idempotency key:
A UUID is commonly used as an idempotency key and it is recommended by many tech companies such as Stripe and PayPal
A new UUID should be generated whenever the request payload changes.
The key is generated by clients and expires after a certain period of time (generally 24 hrs).
To perform an idempotent payment request, an idempotency key is generally added as a HTTP header.
This is how a combination of retries and idempotency keys can help in avoiding double charging the customer!
In the next issue, we’ll dive deep into how Airbnb designed their distributed payments system to avoid double payments 💪.