Stripe integrations done right — real-build patterns
Five Stripe patterns we keep using — subscriptions, security deposits, marketplace payouts, webhooks — and the gotchas worth knowing about.
Stripe integrations done right — real-build patterns
Stripe is the default payments platform we reach for on almost every client build that needs to take money — and we’ve shipped a fair variety of integrations now, from one-shot security deposits for ski chalet operators to ongoing membership billing for community platforms. Here are five patterns we use repeatedly, with the things we wish we’d known earlier.
1. One-off authorisation and capture (deposits)
The Boutique Chalet Company case study is the textbook version: an admin enters a guest’s details and an authorisation amount, the guest receives a secure link, and Stripe places a hold on the card. If the chalet is returned in good condition the hold is released; if not, the chalet operator captures part or all of it.
Three things worth knowing. Authorisations expire — typically after seven days — so the workflow needs to handle re-authorisation if the booking is longer. Strong Customer Authentication adds a 3D Secure step that you have to design for, not retrofit. And the difference between “authorise” and “capture” matters legally as well as technically — be clear with the customer which has happened.
2. Subscriptions with grace periods
For SaaS and membership products, the subscription primitive in Stripe Billing is excellent — but the failure modes are where you earn your money. A failed renewal payment doesn’t mean “cancel the customer immediately”. It usually means “dunning sequence, then grace period, then downgrade or suspend”. We use Stripe’s smart retries plus a custom grace-period state in our own database, so the application can show the right messaging without being tightly coupled to the payment processor.
3. Marketplace and Connect payouts
Anything where money flows in from one party and out to another — bookings platforms, donation platforms, two-sided marketplaces — wants Stripe Connect. The default model is Express accounts, where Stripe owns the onboarding flow and the platform takes a cut. It’s a lot of capability for very little custom code, provided you accept the constraints. Plan around the KYC delays before launch — onboarding a connected account is rarely instant.
4. Webhooks, idempotency, and the “source of truth” question
The bug we see most often in Stripe integrations: the application treats its own database as the source of truth for what’s been paid for, and Stripe webhooks as a notification mechanism. That works until a webhook is missed or delivered out of order. The right model is the inverse — Stripe is the source of truth, and the application reconciles against it. Every webhook handler is idempotent (deduplicated by event ID), and there’s a periodic reconciliation job that catches drift.
5. PCI scope and tokenisation
Use Stripe Elements or the Payment Element on the frontend. Card data goes directly from the customer’s browser to Stripe — your servers never see it. This keeps you in PCI DSS Self-Assessment Questionnaire A scope, which is dramatically less burden than handling card data yourself. We’ve done full PCI DSS Level 1 work for clients who need it (Fund My Masjid, for example), but for the great majority of builds, Elements + SAQ A is the right answer.
The pattern across all five
Treat payments as a distinct domain in your application. Don’t scatter Stripe SDK calls through your codebase — wrap them in a thin service with a clear contract, log every interaction, and design the surrounding state machine assuming things will fail and need to be resumed. Payments code is one of the few places where defensive engineering really earns its keep.