Pure idempotency isn't usually desirable. In any important database table where this can be an issue, you want two timestamps. 1 for when the row was created and 1 for when it was last updated. The upsert should change the ts_updated value, and the attempt should be logged.
If you want genuine pure idempotent interactions, you can't do that, and you have to rely on unique constraints in the database and swallow that particular error, so that nothing about the universe of the application state changes and nothing gets logged.
But that is a pretty garbage way to do things. As with many things, some moderation and flexibility are a good idea.
Instead of focusing on the exact meaning of the word, we should focus on making sure that nothing bad happens if someone does something twice. That's what the operational concept of idempotence is.
It's relatively easy to get something to happen at least one time, and it's slightly less easy to get something to happen at most one time. Getting something to happen exactly one time is really, really hard. That's why we should care: most of the things we want to happen will happen more than once in any nontrivial system.
Purity in concept isn't important. Safety in the sense that nothing bad happens the second or third or nth time around is.
Side note about the Stripe blog linked in the current top post by ageitgey: that's not a useful solution. You can't trust a uuid created outside the context of the uniqueness that needs a guarantee. That's one of the fundamental problems of distributed systems. And it's one I would think Stripe should know better than to espouse since, after all, they did hire aphyr.
You need something closer to home, not something received from a relatively untrusted source. Before you gripe at me and tell me that uuids are, in fact, uuids, let me explain. There are all kinds of situations that can force a client to regen a uuid.
A gas station pump resets because of a blink in power. It remembers all the information about the transaction except for the uuid because the programmer was smart and wanted that to be, well, unique. And he wanted the pump to be smart and retry the failed attempt. Same txn; different uuid.
The user hits the refresh button in the middle of the txn, but the rest of the form data is cached. Not the uuid.
The corner store owner who hates people who use credit/debit cards in general in Queens gets pissed because it takes more than two seconds to process, and pulls the power plug to reset it. Yeah, POS units should clear after that, but they don't always.
User's phone switches from cell service to wifi. Forces a refresh in the app in the middle of a txn. It's still listening for the same transaction response and when it times out tries again with a different uuid.
These are real scenarios that we have to deal with. Trusting a client to only ever retry with the same uuid is not safe. So when I say that you need a uuid in the same context, I mean the uuid created in your database when it receives an auth request, inside the SQL transaction used to create the entry for that attempt.
Everything else about the transaction is used to fingerprint it with the local uuid as the upsert key. Once that is in place, then you can start to have some duplicate txn safety.
That's the beginning of your hell, but it's a better one than trusting client devices.
I'm not trying to take a potshot at Stripe. I have tons of respect for them, but that particular article is misplaced. You can't just pass uuids around and think that you're safe because they are actually unique. I wish it were that simple.
It most definitely is not, as the person said, "the trick."