A valid signature still needs a trust decision
An Oprindo sample had a matching asset hash and a valid signature, alongside an untrusted credential result. The useful story is in those separate answers.
Retrying a purchase, editing its basket and deliberately buying the same thing again can look remarkably similar to a request logger. The intent model has to distinguish them.
A second order for the same paper can be a duplicate or exactly what the customer wanted. One person clicks again because no answer arrived; another buys another pack for a different office. The requests may contain identical values in both cases. Comparing request bodies cannot decide between those intentions because all the submitted values may match. The application needs to remember which purchase the person authorised, not just recognise familiar-looking contents.
A payload hash answers whether the selected fields are the same. It cannot decide whether this is one purchase tried again or two purchases that happen to match. That makes an idempotency key a product decision as well as an API setting. Before generating it, somebody has to choose the point at which a person confirms an intention, what that intention includes and what would count as deliberately starting another one.
AWS’s account of idempotent APIs makes this distinction explicit, including why identical parameters can represent separate intended operations. [1] For a small ordering tool, a useful starting point is a durable checkout intention with a clear confirmation boundary. Its identity survives transport retries. It changes when the person deliberately starts another authorised operation, rather than whenever a network library decides to try again.
In the original teaching example, intention I17 contains one PAPER item, quantity 1, amount 1200 minor units and currency GBP. The submitted payload is recorded with the intention. Its first successful result is order-1. A repeat of I17 with the same payload returns that result. It does not read the current basket and quietly substitute whatever the person has edited since the first request left.
That frozen meaning is important because baskets are working documents. Someone may change quantity from one to two while the original order is still processing. If the retry code serialises the current screen, the same intention now carries a different amount and quantity. Calling it a retry conceals a business revision. The fixture rejects that combination rather than guessing which version the person meant.
Include every field that materially defines the operation, in an agreed representation. Quantity, currency, price basis, destination or recurring terms may matter; a visual note might not. This is not an invitation to hash a convenient subset and assume the rest is harmless. State which fields are frozen and which may change independently. A stable identifier is only useful when the application also preserves what that identifier was intended to mean.
Keep the editable draft separate from the submitted intention and its known or uncertain outcome. Before confirmation, the basket can change freely. Afterwards, the snapshot gives a delayed result something fixed to refer to while the person carries on editing another draft. If quantity 1 was submitted and the screen now shows quantity 2, the old success confirmed quantity 1. Show that submitted amount and quantity in the confirmation. Echoing the current controls can mislead the customer even when the backend has correctly processed one order.
In the second example, I17 arrives with quantity 2 and amount 2400 minor units. The sequential model raises a changed-payload conflict and creates nothing, because this no longer matches the submitted instruction. Generating a new key automatically would permit another purchase without establishing what happened to I17 or whether the person authorised a separate order. The conflict needs a lifecycle decision before another attempt is sent.
The changed-payload conflict is a reason to establish what happened to I17. A completed order may need amendment, cancellation and replacement, or a separate purchase under the business rules. A reliably unstarted one may allow a fresh submission. If its outcome remains unknown, another key does not improve our knowledge of it; it permits another order to exist alongside it. The interface should make that choice visible instead of allowing the retry code to make it for the customer.
Stripe’s API v1 documentation provides a concrete provider contract: it compares parameters associated with an idempotency key, returns the recorded result for a matching request and rejects mismatches. It also describes retention limits and when execution results are recorded. [2] Those details should shape retry code for that API; they do not substitute for the local decision about whether the person is amending an order or starting another one.
A provider’s key and the application’s intention record need not have the same lifespan. An old support enquiry may require the original request-to-order relationship after the provider no longer retains its idempotency entry. Keep the business record and provider references for the application’s justified recordkeeping needs. Do not build a recovery assumption around an unlimited remote memory that the provider contract does not promise.
An original sequential checkout model distinguishes retrying intention I17, changing its payload and deliberately placing another identical order as I18.
Scroll sideways to see all columns.
| Situation | Intent / payload | Expected decision | Why |
|---|---|---|---|
| Connection retry | I17 · PAPER×1 · GBP1200 minor | Return original order-1 | Same authorised purchase |
| Basket edited | I17 · PAPER×2 · GBP2400 minor | Conflict; create nothing | Key no longer describes same request |
| Deliberate second purchase | I18 · PAPER×1 · GBP1200 minor | Create order-2 | Identical contents, new intention |
| First outcome unresolved | I17 unknown; changed basket proposed | Reconcile I17 before new effect | New key cannot erase uncertainty |
The third teaching case starts intention I18 with the same one-pack payload as I17. It creates order-2. This is correct because the scenario explicitly authorises a second purchase; no content comparison can establish that authorisation on its own. The interface should make the distinction understandable, for example by returning to a completed order and offering a clearly labelled purchase-again action.
A double-click while the same confirmation is pending should stay attached to the existing intention. Disabling the button can reduce accidental interaction, but it does not replace a durable association: a page reload, another tab or a delayed response can bypass the visual state. Restore the intention’s known status when the person returns, rather than presenting a pristine confirmation screen as if nothing had happened.
Deriving identity from customer, product and date can suppress a legitimate repeat order or change identity as recovery crosses midnight. Generating a random key for every HTTP attempt has the opposite problem: the provider cannot recognise retries. Create the key at the chosen business confirmation boundary and reuse it for attempts belonging to that intention. Uniqueness is required, but so is the durable association with what the person submitted.
I17’s fixed submission and a later editable basket can contain different quantities.
Follow the labelled arrows. On a narrow screen, scroll sideways if needed.
The downloadable program stores a canonical payload with each intention and returns its saved result for an exact repeat. It makes the submitted snapshot and result available together, so a retry can be answered without consulting a basket that may have changed. The model runs sequentially and makes no external payment call.
Two workers can both read that I17 has no result before either stores it. A real service needs a unique intention constraint and a controlled transition so those observations cannot independently authorise two provider requests. Keep the submitted snapshot and resulting operation linked through the actual provider’s effect and reconciliation rules. The sequential dictionary example defines what a retry means; this shared transition has to preserve that meaning while more than one worker is trying to act.
Expose enough of those meanings to support the person when the operation becomes uncertain. “Order processing; check this order’s status” carries a different promise from “Your request failed; start again.” A support view should connect intention I17, its submitted values, attempts and provider reference, while showing I18 as a separate decision. Otherwise an investigation begins by trying to infer intention from a pile of almost-identical requests.
When support sees two matching baskets, the confirmation history should show whether the customer made two purchases or retried one. That answer needs the submitted values, the intention and its resulting order together. The same record must remain understandable when the screen has changed or the provider’s retry entry has expired, because those are precisely the moments when guessing from request contents would be least helpful.
Working on a workflow like this? Hamsa helps finance and operations teams connect their tools and handle the exceptions, starting with one workflow.
See the Payment Operations PilotPrimary sources behind this article. Living documentation may change.

Practical engineering. A human perspective.
More about Hamsa Software and the person behind it. Editorial notes.