Stack · Stripe
Release testing for Stripe integrations
Payments and plan state arrive as signed webhook events that can be duplicated and can arrive out of order. The checklist sends the events the docs warn about and checks the account state afterwards.
Termswebhook (a message a provider such as Stripe sends to your server when something happens, like a payment) · publishable and secret keys (the publishable key may sit in the browser because row-level security limits it; the secret key bypasses those rules and must stay on the server) · critical flow (a path a user takes that costs money or trust if it breaks: sign-up, checkout, invite, export) · verdict (a one-word release result (pass, pass with findings, fail) with the findings and the checklist version behind it) · CI (the pipeline that builds and tests every change before it can be merged or deployed) · client bundle (the JavaScript your app sends to the browser or ships inside the mobile app; anyone can read it)
What Stripe changes in a codebase
Payments and subscriptions arrive as signed webhook events. Entitlements are only as correct as the handler that verifies, deduplicates and orders those events.
A webhook handler is the most-copied code in a payments integration and the least tested. Every release that touches it runs PY-01 through PY-05 in the provider's sandbox, with unsigned, altered, duplicated and reversed events.
Defaults, from the docs verified 2026-09-21
| Default, from the docs | Why it matters for release testing | Source |
|---|---|---|
| "Without verification, an attacker could send fake webhook events to your endpoint to trigger actions like fulfilling orders, granting account access, or modifying records." Stripe requires the raw request body for the check. | PY-01 sends unsigned and altered events; a framework that parses the body first fails the check silently. | docs verified 2026-09-21 |
| "Webhook endpoints might occasionally receive the same event more than once"; log processed event ids. Stripe "doesn't guarantee the delivery of events in the order that they're generated." | PY-02 replays an event id and reverses a related pair. | docs verified 2026-09-21 |
| Official libraries "have a default tolerance of 5 minutes between the timestamp and the current time"; a tolerance of 0 disables the recency check. | A copied handler that sets tolerance to 0 to make a test pass has removed replay protection; PY-01 includes a stale-timestamp event. | docs verified 2026-09-21 |
| Only publishable keys (pk_) are safe to expose; secret (sk_) and restricted (rk_) keys are not. Sandbox keys start with sk_test_ and live keys with sk_live_. "Don't put keys in source code or configuration files checked into version control." | SC-01 and SC-02 scan for sk_ and rk_ prefixes; SC-04 checks that production is not running on sk_test_. | docs verified 2026-09-21 |
| Restricted keys tagged for autonomous agents are "automatically subject to approval rules, which require a designated reviewer to approve sensitive actions" such as payouts and refunds. | If an agent holds a Stripe key, this is the setting that keeps DR-03 true for money. | docs verified 2026-09-21 |
Each row was read on the linked page on the date shown. Docs change; the date tells you how current the row is. Stripe documentation.
Failure patterns most associated
- criticalWebhook accepted without a signature check
The endpoint that marks orders paid or plans active trusts any request that looks like an event.
- criticalPlan limits enforced only in the UI
The app hides premium features from free users while the API serves them to any caller.
- criticalPrice or amount taken from the request
The checkout call charges whatever amount the browser sent.
- highDebug or test-mode configuration reaches production
Test-mode payment keys, verbose logging or seed data run in production because the configuration was copied from development.
- highSame event processed twice
A delivered-twice event credits a customer twice or sends two emails.
- highHandler assumes events arrive in order
The code expects subscription.created before invoice.paid, and leaves the account in the wrong state when they arrive reversed.
- highRace on balance or inventory writes
Two simultaneous requests both read the old value and both succeed, so a balance goes negative or an item sells twice.
How the checklist adapts
- PY-01 sends unsigned, altered, wrongly signed and stale-timestamp events; the raw-body requirement is the usual reason a copied handler fails.
- PY-02 replays an event id and reverses a related pair, then checks the final state.
- PY-03 and PY-04 edit the client-side plan flag and the checkout amount.
- SC-01, SC-02 and SC-04 scan for sk_ and rk_ prefixes and confirm production is not on sk_test_.
Release checklist, five of the published items
v1.0 · verified on 2026-09-21Webhook signatures are verified against the raw body
automated Send an unsigned event, an event with an altered body, and an event signed with the wrong secret to the webhook endpoint.
All three are rejected with a 4xx status and no state change.
Duplicate and out-of-order events are handled once
automated Deliver the same event id twice and deliver invoice.paid before customer.subscription.created.
Exactly one state change per event id; the out-of-order pair ends in the correct final state.
Cancellation, downgrade and refund paths update entitlements
manual Trigger cancel, downgrade, failed renewal and refund events in the payment provider's test mode and check the account state.
Each event leaves the account with the entitlement the written rules specify, within one webhook delivery.
No secret keys in client bundles
automated Scan the built client assets (JS, source maps, HTML) for known key prefixes and for every value present in the server environment file.
Zero matches for key prefixes (sk_, service_role, AKIA, whsec_, private keys) and zero server-only env values found in client assets.
No secrets in repository history
tool Run a secret scanner (gitleaks or equivalent) over the full git history, not only the working tree.
Scanner reports zero unrevoked findings; any historical finding has a rotation record.
Which plan fits
Starter $2,900/mo
Starter covers all five payment items on a web app. Growth adds the API surface if the integration is behind one.
For 3-8 engineers, weekly releases, web. Limits, cadence and what is not included.
Questions
Stripe webhook testing checklist
How to test Stripe webhooks before going live?
Payment webhook signature verification test
Get a risk list for your codebase
5 business days, $1,200, credited to the first month.