Idempotency: Making Sure a Payment Happens Once
The internet is not a perfectly reliable conversation. Messages get delayed, connections drop and systems retry. A customer double-clicks a pay button. A payment confirmation arrives, our server is slow to answer and the sender tries again. A background job crashes halfway through and the queue runs it a second time.
In most software, a repeated action is a nuisance. In payments, it can mean charging someone twice, crediting a wallet twice or renewing a subscription twice. The defense is a property called idempotency: doing the same operation more than once has the same effect as doing it once.
Idempotency keys for creating payments
When our systems ask the payment processor to create a charge, they include a unique key describing that specific attempt. If the same request is sent again with the same key, because of a retry or a double-click, the processor recognizes it and returns the original result instead of creating a second charge.
The key is tied to the thing being bought, such as a specific invoice or renewal period, not to the moment the button was pressed. That way two clicks on the same invoice share a key, while a genuinely new purchase gets a new one.
Fulfillment is recorded once
Payment confirmations can arrive more than once. When a confirmation arrives, we look up the order it belongs to and check whether it has already been fulfilled. If it has, we acknowledge the message and do nothing else. If it has not, we fulfill it and record that we did, so a second confirmation finds the order already fulfilled and changes nothing.
That pattern protects every paid change: plan access, subscription periods, wallet credits and invoice records.
Renewals that cannot double up
Subscription renewals run on a schedule, which adds another way to repeat work: the scheduled task might run twice, or a person might trigger a manual renewal while the automatic one is in progress. Our renewal invoices are created idempotently for each billing period, so whichever path arrives first creates the invoice and the other finds it already there.
When the outcome is uncertain
Sometimes a request to an outside service ends without a clear answer. The connection dropped after the request was sent, and we do not know whether the other side completed it. Retrying might be safe, or it might duplicate a charge, a domain registration or a paid AI generation.
In those cases we do not guess. The operation is marked as uncertain and locked against replay. A person checks with the provider what actually happened, and only then is the outcome recorded. We cover this pattern in locking uncertain outcomes.
Debits and refunds come in pairs
For usage that is paid from a prepaid wallet, we debit the wallet before calling the paid service and refund it if the call fails. Each debit and refund is linked to the same usage record, so a retried job cannot refund twice or debit twice. You can read more in metered usage with a prepaid wallet.
Testing for repeats
Idempotency is easy to claim and easy to break. When we review payment code, we ask what happens if each step runs twice, out of order or at the same time as itself. Tests send duplicate confirmations and concurrent requests on purpose. If the result is ever "charged twice" or "credited twice," the code is not done.
What customers notice
Customers rarely see idempotency at work. They just never get charged twice, never see a doubled credit disappear and never have to call about a duplicate renewal. That quiet reliability is exactly what money software should provide, and it underpins Pay by Jag and every charge on our platform.
Frequently asked questions
What does idempotent mean?
An idempotent operation has the same result whether it is performed once or many times. In payments, it prevents duplicate charges from retries.
What is an idempotency key?
It is a unique value sent with a request so the receiving system can recognize repeats and return the original result instead of performing the action again.
Can double-clicking a pay button charge me twice?
It should not. Repeated requests for the same purchase share an idempotency key, so the processor returns the first result instead of creating a new charge.
Comments (0)
No comments yet. Be the first to share your thoughts!