Skip to main content
Partly proven

The failure class is proven below — a deliberately buggy handler and a fixed one were run against the same inputs, and they diverged. A fix on your own code has not been proven on this receipt. That is a separate claim, and only prove_fix establishes it — it reproduces the bug on your repository, applies your diff, and re-runs. Call it before you apply the fix, because it needs the still-broken tree.

sandbox · 2eb5d851fd15
11 other runs
Scoped to run run_da21c6c9-679c-4fe4-92aa-2718f592b106.View all 12 runs →
Restored from a saved snapshot — payloads and results are exactly as captured.
2EB5D851FD15 · reference testBug reproduced

Duplicate webhook created a second charge

The same event was delivered twice.

Before the fix
2 deliveries → 2 charges
second delivery created another charge
After the fix
2 deliveries → 1 charge
second delivery recognized as duplicate
3 related checks passed0 unexpected failures2 webhook deliveries tested1 expected error responsetook 2467ms
FetchSandbox reference handlers. Behavioral simulation of a duplicate-webhook handler bug. Stripe delivers at-least-once, so payment_intent.succeeded can arrive 2-3x with the SAME event.id. Both handlers are FetchSandbox reference implementations, NOT your code: the buggy one processes every delivery (double charge), the fixed one dedupes on the stable event id. Apply the brain's fix_pattern (atomic dedup on event.id) to your handler to inherit this behavior.

what changed

The same request, before your fix vs. after — this is what the bug did, and what it does once fixed.

Before the fix
2 deliveries → 2 charges
  1. First deliverycharge 0 → 1
  2. Duplicate deliverycharge 1 → 2
  3. Finaldouble charge detected
After the fix
2 deliveries → 1 charge
  1. First deliverycharge 0 → 1
  2. Duplicate deliverystays 1
  3. Finalexactly 1 charge

request timeline

Before the fix · reference handler
After the fix · reference handler

run timeline

Every request and webhook the run made, in order.

  1. 12:31:41.709POST /v1/customers20033ms
  2. 12:31:41.757POST /v1/payment_intents20040ms
  3. 12:31:41.802POST /v1/payment_intents/pi_GAXMB2ZHA61M6LWRJ42ATUTS/confirm20036ms
  4. 12:31:41.846POST /v1/payment_intents/pi_GAXMB2ZHA61M6LWRJ42ATUTS/capture20035ms
  5. 12:31:41.868GET /v1/payment_intents/pi_GAXMB2ZHA61M6LWRJ42ATUTS20014ms
ok failed webhook

full request history (5)

timetypepath / eventstatusdur

run metadata

sandbox id: 2d64d21288spec: 2eb5d851fd15status: runningscenario: defaultrun id: run_da21c6c9-679c-4fe4-92aa-2718f592b106requests: 5
Generated by FetchSandbox — anyone with this link can read the proof.