At Modern Treasury, we place a strong emphasis on building systems that behave predictably and are resilient to failures. An important characteristic of these systems is that they are idempotent. In this article, we’ll explain what being idempotent means and why it is important for systems that handle payments like we do at Modern Treasury.
The word idempotent stems from the Latin words idem and potent, which when put together, means the same power . The term was originally introduced in mathematics to refer to mathematical operations that can occur multiple times while only altering the end result once. For example, the operation “Multiply by 1” is idempotent. Whether you do 2x1 or 2x1x1x1, the result will always be 2.
This behavior is desirable in internet applications, especially those that involve payments. When you are shopping online and press the submit button on a checkout page twice, you only want your order to be placed once.
When building a system to move money, it is paramount that operations that move money are idempotent. Failure to do this might result in accidentally double charging your customer, or paying a vendor multiple times. The risk of this happening is elevated based on the way software is typically built today, since developers take advantage of scalable systems that process multiple items in parallel.
At Modern Treasury, we have a two-pronged approach to idempotency.
The first part relates to our internal systems. We use state machines to keep track of the current status of any payment. State machines enforce the sequence of steps a payment can take, so that a payment cannot be processed twice, for example . Our state machine is reflected in our API documentation, and we’ve included it here as well .
Every critical operation in our system is wrapped in a database transaction. Database transactions should be used when you are recording multiple items in your database. For example, when we create a payment that needs to be approved, two objects are created in our database: the payment and the pending approval. If either one of these objects is not created because of an error, the other one should not be either. Database transactions help us ensure that if a critical write fails part way, we completely roll it back so there isn’t inconsistent data.
We also guard against the risk that two asynchronous jobs process the payment at the same time. We use mutexes  that ensure at most one job is operating on a payment at a time.
We recommend that our customers build similar safeguards into their own systems, even when they are using Modern Treasury.
Idempotency in our API
The second part of our idempotency strategy is externally facing and built into our API. When our customers use our API to programmatically create payments, there is a risk that they might send the same API call multiple times. This is especially likely if their systems don’t have proper safeguards like those described above.
Our API supports creating payments via HTTP POST requests, which are not idempotent by default . To make these requests idempotent, a customer may pass a unique key in the request headers when initiating a payment . Our system records the key alongside the API request and its results for 24 hours. If our customer initiates the same API call multiple times within 24 hours, we will simply send back the original response without re-performing the payment.
We chose 24 hours because we believe the role of idempotency keys are to solve for short-term bursts of the same API calls. They aren't meant to be an architectural crutch for our customer's systems. Our customers should build their systems using the techniques described in the prior section and only view idempotency keys as a last resort safety measure. In fact, we’ve discussed with customers making these keys last longer than 24 hours and the overwhelming feedback we received was that 24 hours was sufficient.
Put together, this two-pronged approach helps our customers safely process payments.
If you’re interested in learning more about idempotency and payments, reach out here for a demo of Modern Treasury.
“Mutex” is short-hand for “mutual exclusion”. Imagine there is a fork on the table. If your friend picks up the fork, you cannot pick it up until they put it down. Mutexes operate similarly in computers by ensuring that multiple processes don’t act on the same data at once. For more details: https://en.wikipedia.org/wiki/Lock_(computer_science)