Skip to content

Billing

Stripe hosts the payment pages and the billing portal. Your plans are written in code, and a workspace changes plan only when Stripe's signed webhook says so.

In short

  • Stripe Checkout and customer portal: your server never sees a card number.
  • Plans and prices live in one file; one command copies them to Stripe.
  • Plans are shown without a Stripe account until you switch billing on.

Your plans are code

The plans and their prices sit in one list, shared by the server and the web app. One command creates the matching products, prices and portal settings in Stripe; running it again changes nothing.

  • A new amount creates a new price; subscribers keep theirs until they change plan
  • The command refuses a live Stripe key unless you add --live
  • Monthly and yearly prices, in euros until you change one constant
packages/app-shared/src/constants/Plans.ts
  {    key: 'pro',    monthlyPriceInCents: 1200,    yearlyPriceInCents: 12000,    memberLimit: 20,    isHighlighted: true,  },
The example plans, read from the same file
PlanMonthlyYearlyMembers
Free€0€0Up to 3 members
Pro€12€120Up to 20 members
Business€29€290No limit

Checkout and portal, hosted by Stripe

"Upgrade" opens Stripe Checkout. Once subscribed, a plan change opens Stripe's portal on a confirmation with the prorated amount, and "Manage billing" opens it for cards, invoices, billing details and cancellation.

  • Only admins open Checkout or the portal; members see the plan and its status
  • Stripe shows the payment methods you turn on in its dashboard
  • A workspace never gets a second subscription
  1. An admin clicks UpgradeThe server first asks Stripe whether the workspace already pays for a plan.createCheckoutSession
  2. Stripe Checkout takes the paymentOn Stripe's page, in the person's language. Your server never sees the card.
  3. Stripe sends a signed webhookThe server checks the signature, stores the event and answers at once.POST /webhooks/stripe
  4. The worker syncs the subscriptionIt reads the customer's subscriptions from Stripe and saves what Stripe says now.
  5. The new plan is in forceThe Billing page, which checks every 2 seconds after a payment, shows it.

Webhooks in an inbox, handled in the background

Every Stripe event is checked, stored once in an inbox table and handed to the background worker. The worker re-reads the subscription from Stripe each time, so an event that arrives late, twice or out of order gives the same result.

  • The checkout success page grants nothing: anyone can open its address
  • A failed job is retried 10 times, with growing delays; a cron picks up any event left behind
  • An unpaid workspace keeps its plan for a grace period, 14 days by default

Plans that set the team size

Each plan can cap its number of members. From a workspace's first request, and after every plan change, a background job gives its plan's limit to its Clerk organization, and Clerk's invitation screens refuse anyone beyond it.

  • The limits sit in the same list as the prices
  • Setting the same limit twice changes nothing, so the job is safe to repeat

Disputes and refunds, never missed

When a customer disputes a payment, a bank warns of fraud or a payment is refunded, the app records it with the workspace concerned and alerts you, with a link to the Stripe Dashboard and what to do before the deadline.

  • Access never changes by itself: you decide, in Stripe
  • Alerts reach you in the logs, and by email once Sentry is connected
When money comes back, or may
What happenedAlertWhat you do
A dispute is openedError, with the deadlineAnswer it in Stripe before the deadline
An early fraud warningErrorRefund the payment, so it can't be disputed
A dispute is closedError if lost, warning if wonCancel the subscription if you want to
A payment is refundedWarningUsually nothing

Questions

Do I need a Stripe account to start?

No. With billing off, the default, the Billing page shows your plans with "Soon" buttons and everything else works. Switch it on with a Stripe sandbox when you're ready.

Does it handle taxes?

Stripe Tax does, once you have a tax registration: your registration in Stripe, then a few lines in one file, listed step by step in the billing guide. An accountant should confirm the rules for your country.

Are refunds and disputes handled?

Yes. Disputes, refunds and early fraud warnings are recorded with the workspace concerned, and you get an alert with a link to the Stripe Dashboard and what to do. Access never changes by itself: you stay in control.

Start your next app from a clean base

Pay once and get the full source code, with every future update.