In APIs, idempotency is an important concept while implementing a payment system. An idempotent endpoint is one that can be called any number of times while guaranteeing that the side effects will occur only once. In terms of the payment system, it prevents multiple debits from the same account during failures.
The Problem
Let's discuss the problem first. Whenever we have payments in our system, we need to take care of various scenarios such as payment failures, request timeout and catastrophic events.
Let's say Client A is making a payment. Client A will make a request to a server for debit from his account. Now, there will be three scenarios,
Client A request got successful and payment successfully completed.
Client A Request got failed, before completing the transaction.
Client A request got failed, after completing the transaction.
Scenario (1) is also absolutely fine as the payment got successful and the money got debited from the client’s account. The server will give 200 response code and client will show payment successful.
Scenario (2) is absolutely fine as it got failed before the transaction. The server will give back the appropriate error code and message to the client and the client will reinitiate the payment.
Scenario (3) is a problem that we need to address. Here payment has been successfully processed and the money has been debited from the client’s account, But the request got failed after this, due to above mentioned reasons. So, the server will give error code in response to the client, the client will assume that payment got failed, hence will reinitiate the request and server will debit the money from the client’s account twice.
The Solution
In order to ensure a single debit occurs from the client’s account, the Server would need to know a lot about the use-cases of the client and maintain a state of a system on server side, which is not a scalable and appropriate solution. Instead, the client can provide a unique identifier for each unique interaction with the server. For example, if each payment request has a unique id, the Consumer can pass that id along with the payment request. The Server will then make sure it does not serve the same request twice.
In the above problem, let’s say client will make a payment request with an id, server completed the payment successfully and then the request got failed. Now the client will again retry the payment request with the same id, the server will check whether a request with the same id has been successfully completed or not, if it is it will not initiate the payment and if it's not it will complete the payment and send a response to the client appropriately.
The unique id that we send with every request if known as idempotency key.
Enable Idempotency
To submit a request for idempotent processing, send a request with the Idempotency-Key:<key> in the header. The <key> is a unique identifier for the message with a maximum of 64 characters. If you don't receive a response (for example, in case of a timeout), you can safely retry the request with the same header.
Invalidate idempotency keys after a pre-defined time period, therefore after the time period passes the request is treated as a new non-idempotent request.
Idempotency key can be of any value such as a combination of timestamp and user information or device information, using SSO for the application. Most recommended is the use of a UUID as an idempotency key.
While retrying client can use the exponential backoff algorithm to prevent server overload in case of huge traffic.
The client should avoid continuous polling mechanism for Asynchronous payment transactions, instead use a messaging queue on the publisher-subscriber architecture, anyways asynchronous payment system is a different topic altogether.
You can reach out to me on ohm.patel1997@gmail.com.
Comments