Decision guide
Almost every SaaS discovery we run ends with the same question: how do we get people to pay, and how does the product know who may do what? It sounds like two features. In practice it is one connected model — and mistakes here cost more than most UI decisions.
We do not build payments from scratch. We connect Stripe, auth, and your data model in a way you can own, debug, and extend — without waking up to double billing, stuck trials, or users seeing each other's data.
TL;DR
Key takeaways
- Stripe handles cards, invoices, and self-service — your job is to mirror subscription status in the product reliably.
- Organisation (workspace/team) must be the core of auth from day one, not an add-on when customer number two arrives.
- Webhooks with idempotency are not optional. Stripe redeliveries happen — plan for them.
- Customer Portal saves support time: cards, invoices, and plan changes belong with Stripe, embedded in your UI.
- SSO and advanced roles can wait — but org ID on every row cannot.
Why billing and auth belong together
A paying customer is rarely one user. It is an organisation with an admin who bought, a colleague who needs inviting, and maybe an accountant who needs to fetch invoices. If the auth model only knows "user", and billing only knows "Stripe customer", you end up with manual fixes every time someone changes jobs or adds a team.
The model we recommend is simple to describe and hard to retrofit: every business entity belongs to an organisation. Users belong to organisations via membership with roles. Stripe Customer (or Subscription) points to the organisation — not to a single user, unless you deliberately sell B2C without teams.
The product reads access from your database, not directly from Stripe on every request. Stripe is the source of truth for payment; your app is the source of truth for what the user may see and do. Synchronisation happens via webhooks and a small, testable state machine — not ad hoc calls in the checkout flow alone.
Stripe patterns vs. building it yourself
Proven Stripe stack
Subscriptions, Customer Portal, webhooks, and test mode — what Stripe has refined over years.
- PCI: card data never touches your servers
- Trials, upgrades, and pro-rata handled by Stripe Billing
- Customer Portal for cards, invoices, and cancellation
- Test mode and fixtures for CI without real cards
- You own the business logic — Stripe owns the payment infrastructure
Roll-your-own billing
Custom invoice engine, manual card handling, or home-built subscriptions.
- Long time before the first real payment goes through
- Compliance and edge cases (chargebacks, failed payments) become your problem
- Self-service must be built and maintained
- Hard to change pricing model without migration
- Typically only defensible if payment is core differentiation — it rarely is
The sequence we recommend
Do it in this order. Do not skip webhook handling for checkout UI.
- 01
Organisation and membership first
Model org, user, invitation, and roles. The session knows the active org. All business data has org ID — even while you only have one test customer.
- 02
Stripe products and prices in the dashboard
Create products, prices, and any trials in Stripe. Keep IDs in config — do not hardcode amounts in the app. Pricing changes should be possible without deploy.
- 03
Checkout or Payment Link for the first sale
Get one path to payment in production early. Checkout Session with client_reference_id or metadata binding to org ID. Verify that success URL and webhook agree on state.
- 04
Webhook endpoint with idempotency
Receive events, store event ID, update subscription status on org. Handle invoice.paid, customer.subscription.updated, and deleted. Log errors and dead-letter — redeliveries happen.
- 05
Customer Portal embedded
Give admins a place to update cards and fetch invoices without a support ticket. Portal session created server-side; return URL points back into the product.
- 06
Feature gates from plan
Map Stripe price/product to entitlements in your DB. The app checks entitlements — not the Stripe API — on every protected call. That makes tests and offline flows simple.
Auth provider: Auth.js, Clerk, or WorkOS
The choice matters less about logos and more about where you are heading. Auth.js gives full control and low licence costs — you pay in implementation time and maintenance. Clerk is fast to get started with for B2C and simple teams. WorkOS is aimed at B2B with SAML, SCIM, and audit — good when enterprise contracts are on the roadmap, not when they are already signed.
Regardless of provider: org and membership must be your domain model, not just a field in the auth provider. The provider authenticates identity; your app authorises what that identity may do in which org. Do not conflate "logged in" with "may edit this tenant".
SSO can wait until the first customer requires it in the contract — if the org model already exists. What cannot wait is that all tables have org scope and that you can explain in due diligence how data is isolated.
Questions we get again and again
Should we use Stripe Billing or Stripe Payments alone?
For SaaS with subscriptions: Billing. Payments alone fits one-off purchases. Billing handles trials, renewals, failed payments, and plan changes. Building subscription logic on top of one-off payments is the kind of project that looks simple in week one and becomes a maintenance nightmare in week twenty.
How do we test webhooks locally?
Stripe CLI forwards events to localhost. You run test-mode keys, simulate checkout, and assert that org status updates idempotently. Add CI tests that replay stored event payloads — not just manual click tests in the dashboard.
What about usage-based pricing?
Stripe Metered Billing covers many models. You still need to report usage reliably and map it to org. Often start with simple plans (flat or per-seat) and introduce metered when you know what customers actually consume. Complex pricing early slows sales and code.
Can one user belong to multiple organisations?
Yes — and you should plan for it, even if v1 only has one org per user. Membership as a join table with active org in session makes later consultancies and agency scenarios possible without an auth rewrite.
When do we need an admin panel for billing?
Stripe Dashboard is your admin panel at first. Build internal tools when support repeatedly has to do the same thing manually — typically refund, plan override, or "this org needs a trial extended". Automate what happens often; leave the rest in Stripe.
Need payments in production?
Let us design billing and auth before you accept cards.
We will go through your pricing model, org structure, and Stripe setup — and say what belongs in v1, and what can safely wait.
