Plans, billing and selling it as SaaS
The Free, Pro and Accountant plans and what each unlocks, the 14-day trial, Stripe setup and webhook events, and which licence you need to charge customers.
5 min readUpdated Oct 17, 2026Applies to Subsweep 0.1.0
Subsweep can run as a multi-tenant service: businesses sign up, each gets its own workspace, and you bill them through Stripe. For a single-business install you can ignore everything here except the trial note.
Important
Check your licence first. On CodeCanyon, the Regular License covers one end product whose end users are not charged. If your customers pay to use what you build with Subsweep (a subscription, a setup fee, any paid plan), you need the Extended License. Read Envato's licence terms for the authoritative wording; this note is a summary, not legal advice.
Plans
| Free | Pro | Accountant | Accountant client | |
|---|---|---|---|---|
| How a workspace gets it | When a trial ends without a Stripe subscription, or a subscription is cancelled | 14-day trial on sign-up, or Stripe Checkout | Stripe Checkout | Created from an accountant's Clients screen, which needs an active Accountant plan |
| Subscriptions | Up to 10 added by hand or quick add | Unlimited | Unlimited | Unlimited |
| Manual add, quick add, UPI form, statement upload | Yes | Yes | Yes | Yes |
| Bank feeds and email scanning | No | Yes | Yes | Yes |
| Savings figure and flag details | Blurred | Yes | Yes | Yes |
| Reminders, alerts and digests | No | Yes | Yes | Yes |
| CSV and PDF export | No | Yes | Yes | Yes |
| Shareable report | Yes | Yes | Yes | Yes |
| Clients screen | No | No | Yes (for accountant accounts) | No |
An Accountant client workspace has the features in its column only while the accountant's own workspace is on Accountant; otherwise it is treated as Free.
On Free, the Reveal screen's button becomes Unlock savings and opens an upgrade dialog, Connect bank opens Settings → Billing, and adding an eleventh subscription by hand is refused with a message naming the limit.
Note
A few plan rules are softer than the table in 0.1.0: the Free cap applies to hand-added and quick-added subscriptions but not to ones detected from a statement; the blur on Free is visual only, so the real figures are in the page data; and the Pro "3 team seats" is a label, not a limit. Details are on Known limitations.
The trial
Every new workspace starts on Pro with a trial ending 14 days later. No card is needed. When the date passes and the workspace has no Stripe customer, it becomes Free on its next page load or hourly run. Nothing is deleted; the list stays, and features above the Free line lock until the Owner upgrades.
Prices
The prices customers see are text in the source code, and the amounts charged are Stripe prices. They are not linked, so change both together:
| Where | Default |
|---|---|
| Labels in the app and on the pricing page (see Values that live in code) | Pro $24 a month or $199 a year; Accountant $15 per client a month, minimum 3 |
Prices created by scripts/setup-stripe-prices.mjs |
The same amounts, in USD |
To charge a different amount or currency, create the prices in Stripe yourself (or edit the script), put their IDs in the environment, and edit the labels to match. Look up Stripe's fees on stripe.com/pricing.
Stripe setup
Without Stripe, plans and the trial still work, and paid upgrades show "Billing isn't available yet. Contact us and we'll set your plan up by hand." Stripe adds self-serve upgrades.
Get your secret key from the Stripe Dashboard (Developers → API keys). Start with a test key (
sk_test_...).Create the products and prices. Either run the bundled script, which reads
.env(not.env.local):npm run setup:stripe # or, without a .env file: STRIPE_SECRET_KEY=sk_test_... node scripts/setup-stripe-prices.mjsIt creates (or reuses) a Subsweep Pro product with monthly and yearly prices and a Subsweep Accountant product with a monthly per-client price, then prints the three lines to paste:
STRIPE_PRICE_PRO_MONTHLY=price_... STRIPE_PRICE_PRO_YEARLY=price_... STRIPE_PRICE_ACCOUNTANT=price_...Add a webhook endpoint in Stripe for
https://<your domain>/api/webhooks/stripewith these events:checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deleted
You can also add
invoice.paid. It is optional: it keeps the plan the workspace already pays for, so an Accountant workspace stays on Accountant.Set the keys:
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET(the endpoint's signing secret) and the three price IDs. Restart, or redeploy on Vercel.STRIPE_WEBHOOK_SECRETis required: without it the webhook refuses every event, and plans never change after checkout.Turn on the customer portal in Stripe (Settings → Billing → Customer portal) so Customer portal can update cards and cancel.
Test with Stripe's test card
4242 4242 4242 4242, then switch to live keys and a live webhook.
What customers experience
- Only Owners can buy. Settings → Billing offers Upgrade to Pro · monthly, Pro · yearly and Accountant · 3 clients.
- Checkout is a Stripe subscription and accepts promotion codes. Customers return to Settings → Billing, and the plan changes when Stripe's webhook arrives, usually within seconds.
- Customer portal opens Stripe's portal once the workspace has a Stripe customer.
| Stripe event | Effect on the workspace |
|---|---|
| Checkout completed, subscription created or updated | Plan set to Pro or Accountant, and the Stripe customer, subscription, price and quantity are saved. For Accountant, the workspace's Owners also get accountant mode |
| Invoice paid (optional) | Plan read from the invoice's subscription details or price; otherwise an Accountant workspace stays on Accountant and any other becomes Pro |
Subscription updated to canceled, unpaid or incomplete_expired |
Plan set to Free |
| Subscription deleted | Plan set to Free |
Payment failed or subscription past_due |
No change: the paid plan stays until Stripe cancels the subscription |
The webhook checks every event's signature against STRIPE_WEBHOOK_SECRET, with a five-minute tolerance, in every environment and whether or not STRIPE_SECRET_KEY is set. Without the secret it answers 503 and changes nothing; an unsigned or wrongly signed event, or a payload it cannot read, gets 400. Setting a plan by hand is covered under Operator tasks.
Before you launch a SaaS
- Buy the right licence (see the top of this page).
- Leave
DEMO_LOGIN_ENABLEDunset (the demo is off in production), and remove the demo account if it was ever on (how). - Configure outbound email. Without it, production refuses email sign-up and magic links, and invites, reminders and digests cannot be delivered.
- Configure Stripe fully, including
STRIPE_WEBHOOK_SECRET, or plans will not change after checkout. - Replace the short built-in Terms and Privacy pages (
app/(marketing)/terms/page.tsxandapp/(marketing)/privacy/page.tsx) with your own, and update the brand name if you rebrand. - Only offer the integrations that work in this version: see Integrations. Plaid, Gmail and Google sign-in may need the provider's approval before the public can use them.
- Read Known limitations so your own sales pages promise only what the product does.