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
{ key: 'pro', monthlyPriceInCents: 1200, yearlyPriceInCents: 12000, memberLimit: 20, isHighlighted: true, },| Plan | Monthly | Yearly | Members |
|---|---|---|---|
| Free | €0 | €0 | Up to 3 members |
| Pro | €12 | €120 | Up to 20 members |
| Business | €29 | €290 | No 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
- An admin clicks UpgradeThe server first asks Stripe whether the workspace already pays for a plan.
createCheckoutSession - Stripe Checkout takes the paymentOn Stripe's page, in the person's language. Your server never sees the card.
- Stripe sends a signed webhookThe server checks the signature, stores the event and answers at once.
POST /webhooks/stripe - The worker syncs the subscriptionIt reads the customer's subscriptions from Stripe and saves what Stripe says now.
- 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
checkout.session.completedProcessedcustomer.subscription.createdProcessedinvoice.paidProcessedorganizationMembership.createdProcessedcustomer.subscription.updatedQueuedPlans 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
| What happened | Alert | What you do |
|---|---|---|
| A dispute is opened | Error, with the deadline | Answer it in Stripe before the deadline |
| An early fraud warning | Error | Refund the payment, so it can't be disputed |
| A dispute is closed | Error if lost, warning if won | Cancel the subscription if you want to |
| A payment is refunded | Warning | Usually 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.
Explore the other features
- Sign-in and workspacesClerk accounts, teams and roles checked in your code.
- AI guardrailsA rulebook, lint rules that explain, and yarn verify.
- Design system70 components, 466 icons and tokens for light and dark.
- ArchitectureOne repository: web app, API, worker and shared code.
- SecurityLocked endpoints, rate limits, backups, alerts.
Start your next app from a clean base
Pay once and get the full source code, with every future update.