Open-source prototype · early validation
Break your payment integration before production does.
PaymentChaos sends provider-accurate webhook deliveries through duplicates, stale ordering, delays, and concurrent retries—then checks whether your application’s business state is still correct.
01Failure modes
Three deliveries. Three costly assumptions.
Every delivery returns 200. The damage is in your database.
- Duplicate
One renewal grants twice
The provider retries an event after a lost acknowledgement. Both deliveries return 200, but an entitlement is inserted twice because processing is not idempotent.
- Stale state
An old cancellation wins
A delayed cancellation arrives after a newer renewal. Code that trusts arrival order revokes a subscription that is currently active.
- Concurrency
Retries race the check
Concurrent deliveries both pass a check-then-insert guard before either writes. A duplicate slips through because the operation is not atomic.
02Real run · seed 1337
The naive app fails. The corrected app passes.
A committed transcript of the real CLI delivering the same Stripe renewal scenario to both example applications. Event IDs, ports, and latencies vary by run.
$ pnpm --filter @paymentchaos/golden-e2e demo
$ node --experimental-sqlite --import tsx src/demo.ts
PaymentChaos golden demo (seed=1337, engine=cli)
=== stripe-express-naive (expect business failure) ===
seed 1337
Deliveries
#0 invoice.paid evt_Ez15z8nnits3DNqYBWZYTbr6 attempt 1 200 22.9ms reorder,concurrent
#1 invoice.paid evt_Ez15z8nnits3DNqYBWZYTbr6 attempt 2 200 20.7ms reorder,concurrent
#2 invoice.paid evt_Ez15z8nnits3DNqYBWZYTbr6 attempt 3 200 20.7ms reorder,concurrent
#3 invoice.paid evt_Ez15z8nnits3DNqYBWZYTbr6 attempt 4 200 1.3ms duplicate,reorder
#4 invoice.paid evt_Ez15z8nnits3DNqYBWZYTbr6 attempt 5 200 1.2ms duplicate,reorder
#5 customer.subscription.updated evt_Ez15z8nnwbotm5Xu1xskc1DM attempt 1 200 32.0ms reorder
Assertions
✓ every validly signed delivery is accepted
✗ The assertion command exited with 1 after 1 attempt(s).
✗ Duplicate invoice.paid delivery created 5 entitlement records.
expected: 1
observed: 5
✓ subscription_active
✗ Duplicate invoice.paid delivery created 5 renewal ledger entries.
expected: 1
observed: 5
✓ subscription_stripe_id
reproduce: node <repo>/packages/cli/dist/bin.js run stripe-subscription-renewal --seed 1337
PAYMENTCHAOS FAILED seed=1337 plan=dcc5…
naive exit 1 (expected)
=== stripe-express-correct (expect pass) ===
seed 1337
Deliveries
#0 invoice.paid evt_2KgYDkv6its3DNqYBWZYTbr6 attempt 1 200 11.1ms reorder,concurrent
#1 invoice.paid evt_2KgYDkv6its3DNqYBWZYTbr6 attempt 2 200 8.8ms reorder,concurrent
#2 invoice.paid evt_2KgYDkv6its3DNqYBWZYTbr6 attempt 3 200 8.8ms reorder,concurrent
#3 invoice.paid evt_2KgYDkv6its3DNqYBWZYTbr6 attempt 4 200 1.2ms duplicate,reorder
#4 invoice.paid evt_2KgYDkv6its3DNqYBWZYTbr6 attempt 5 200 1.1ms duplicate,reorder
#5 customer.subscription.updated evt_2KgYDkv6wbotm5Xu1xskc1DM attempt 1 200 1.3ms reorder
Assertions
✓ every validly signed delivery is accepted
✓ assert.command exits 0
✓ renewal_entitlements
✓ subscription_active
✓ renewal_ledger
✓ subscription_stripe_id
Notes
All 1 repetition(s) passed. Concurrent deliveries interleave nondeterministically on your server, so this lowers but does not rule out the chance of a race. Raise repeat to test harder.
PAYMENTCHAOS PASSED seed=1337 plan=dcc5…
correct exit 0 (expected)
Download the 35-second terminal recording (.cast)
Captured CLI output, paced for readability. Replay with asciinema play demo.cast.
03How it works
Test the invariant, not just the response.
- Scenario
Choose a provider lifecycle
Start from a built-in lifecycle such as a Stripe subscription renewal, or describe a versioned scenario in YAML.
- Chaos
Apply deterministic failures
Duplicate, reorder, delay, or release deliveries concurrently. The seed reproduces the same delivery plan and plan hash.
- Assert
Check application state
Run your own verification command after delivery. Exit codes make failures useful in local scripts and CI, while optional JSON checks explain what changed.
04A different job
Beyond capture and replay.
Capture-and-replay tools are useful for inspecting and resending HTTP traffic. PaymentChaos answers a complementary question: can a deterministic sequence of provider-shaped deliveries corrupt business state?
- Provider-aware generation. Correct event shapes, raw bytes, and signatures for controlled test data.
- Purposeful failure schedules. Composable operators model duplicate, reordered, delayed, and concurrent delivery.
- Business-state verdicts. Your command checks entitlements, subscriptions, ledgers, or any invariant your app owns.
05Early access
Help validate PaymentChaos.
Try the source checkout today. PaymentChaos is not published to npm yet. Join the list for early-access updates and guided testing.