Back to roadmap
US-1188
Billing Webhooks
IN PROGRESSAgent working · step 1 of 5Last verified 4 min ago
User story
stripewebhooksidempotent
Channels & integrations · auto-detected from this story
In-appSStripe
Acceptance criteria
2 / 3 verified
Each scenario is run as a Playwright test by the QA agent
Scenario 1: Webhook updates subscription state Verified
Givena webhook with a valid Stripe signature
Whenan invoice.paid event arrives
Thenthe subscription is marked active and the ledger is updated
Scenario 2: Duplicate webhooks are ignored Verified
Givenan event id that was already processed
Whenthe same event arrives again
Thenit is acknowledged with 200 without double-applying
Scenario 3: Invalid signature is rejected Failing
Givena tampered payload
Whenit reaches the webhook endpoint
Thenit returns 400 and is logged for review
QA agentPlaywright· ran 4 min agoView run
Expected the assertion to hold · Actual: mismatch
Likely cause: Retry & Fallback Flow
Spec quality · craft learnings applied
9/10 passingGeneralisable rules the agent applies to every spec — they grow from review feedback & flaky scenarios, and act as a self-improving linter.
Assert one outcome per scenarioAtomicity
Each scenario asserts a single outcome
One trigger per scenarioAtomicity
Every scenario has exactly one trigger
Keep implementation out of Given/When/ThenClarity
Scenario 1 names an implementation detail (“webhook”)
Scenarios describe behaviour, not mechanism — naming the tech couples the spec to today's design and ages it.
Make every outcome machine-checkableTestability
Outcomes are concrete and observable
Bound time-sensitive outcomesTestability
Time-sensitive outcomes carry a bound
Pair every happy path with a failure pathCoverage
An explicit failure / edge scenario is present
Assert the negative spaceCoverage
At least one scenario asserts the negative
State actor, capability and benefitClarity
Story names actor, capability and benefit
One promise per storyScope
The story makes a single promise
Keep the slice thinScope
3 scenarios — a thin, shippable slice
Decisions · trade-offs captured
DR-08 · Idempotent webhook handling
Stripe re-delivers webhook events; naive handlers double-charge.
Idempotency keys persisted in Postgres with an outbox processor.
Learnings applied · from the library
Webhook consumers must be idempotenthigh
External webhook integrations re-deliver; always add a duplicate-delivery scenario and an idempotency decision.
Learned from US-1188 · INC-090 (duplicate charges)
Related specs · graph neighbours