Build1 publisher2 min readPublished
One SQLite transaction keeps a retried Buy click from creating a second order
Retried Buy clicks get the original order back in a dev.to guide that commits each order with its attempt key in one SQLite transaction. A disabled button only cuts double-clicks, and the guide's available text ends before it covers charging the card.
The Engineer · Build desk

What happened
- A dev.to guide on checkout retries says disabling the Buy button or aborting the browser request cannot establish that the server stopped working.
- In its design the server issues a quote ID for the offer, and the browser generates one idempotency key per logical purchase attempt.
- A retry with the same customer, key and quote gets the stored result back, while the same key sent with a different quote is rejected.
- The guide requires the order and its stored receipt to commit together in one transaction, or neither commits.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint Client code holds part of the guarantee. A fetch helper that mints a new key on every call gives each retry a new identity, and the server cannot tell it from a fresh purchase.
- cost Every purchase endpoint needs a durable receipt store that compares each retry with the original request. With quote_id as the only field the comparison is easy; each field added to the request makes it harder.
- decision Teams adapting the pattern for repeat purchases have to settle what counts as the same purchase before they can drop the one-quote, one-order constraint.
The guide starts from code that looks reasonable [12]:
``` if not receipt_exists(customer, key): order = create_order(quote) save_receipt(customer, key, order) ```
Two requests can both run the check before either one saves anything. Both see "not found," and both create an order [12]. The second failure needs no concurrency at all. The process can stop after it creates the order and before it saves the receipt [13]. When the retry arrives, the key has no receipt and the order already exists [13].
The runnable example handles both cases in one transaction on Python's standard-library SQLite [14]. The author picked it to keep installation simple while still using a real database instead of an in-memory dictionary [14]. A dictionary is a fine idempotency store until the process restarts. The transaction opens with BEGIN IMMEDIATE and looks up this customer's stored attempt before it creates anything. A match is either rejected as a different request or answered with the stored result [14].
The request leaves the browser very little to decide. The illustrative call is a POST to /purchases with an Idempotency-Key header and a body of {"quote_id":"quote_123"} [18]. The server takes the customer from authentication and the scope and price from its own quote record [7]. The guide adds that knowing a quote ID is not permission to use it, and points to OWASP's transaction authorization guidance for that boundary [7]. Quotes are immutable in the example, so a changed offer means a new quote [3].
If I were adopting this design, the unique constraint on the order's quote ID is the piece I'd keep even behind a framework that manages idempotency keys for me. A key identifies repeat deliveries of one attempt. The guide's point is that idempotency cannot know two different keys were meant to describe the same intent [10]. A request that arrives under a new key for an already-used quote is a new attempt as far as the receipt table knows. The constraint is what stops it becoming a second order [10].
Charging the card is the other half. The guide frames its subject as the boundary between creating an order and charging for it [15]. I think each side of that boundary needs its own key. The receipt records that an order exists. The charge is a separate write at a separate party, the payment provider. The guide says it will open up the payment-provider layer [15]. The available text ends partway through the SQLite transaction sequence, before that section begins [17].
What to watch
- The guide's payment-provider section: whether the card charge carries its own idempotency key tied to the order, or reuses the purchase-attempt key.
- How the example recovers a pending attempt after a page reload, which the guide says the application must do before checking the attempt's status.