Billing, sign-in & email setup
Turn on paid plans with Stripe, configure Google/GitHub sign-in and support email.
Pricing and costs
Launch prices, flat per workspace (the billing code charges one Stripe price per workspace, so member caps stand in for per-seat pricing):
| Plan | Per month | Orgs | Members | CI jobs | Deployments / month | Backup storage |
|---|---|---|---|---|---|---|
| Free | $0 | 3 | 3 | 2 | 100 (no backups, no test monitoring, no data deploys) | 1 GB |
| Team | $149 | 10 | 5 | 25 | 5,000 | 5 GB |
| Business | $349 | 30 | 15 | 100 | 20,000 | 25 GB |
| Enterprise | quote | unlimited | unlimited | unlimited | unlimited | unlimited |
Backup storage is counted from the files a workspace's backups, snapshots, archives and deployment packages point at. At the limit, new backups pause (scheduled, record, archive and Marketing Cloud ones; manual backups are refused with a clear message), the owners get an email at most once a week, and nothing is deleted. Free trials and billing-off have no limit.
For scale, Gearset charges roughly $215 to $320 per user per month for DevOps, plus separate backup fees, so 5 users cost $1,000 to $1,600 a month there against $149 here. Yearly billing at ten months' price (two free) is the plan once Stripe is set up. Existing databases pick up the change through migration 29 (only while the old $99 "Pro" plan is untouched and has no Stripe price); Admin → Plans always has the last word.
Add-ons (paid plans only): a workspace can add capacity on top of its plan, billed per unit each month. Launch prices: Extra backup storage is $10 per 10 GB, and Extra deployments is $20 per 5,000 a month. Each unit is one more line quantity on the Stripe subscription, prorated for the current month; the owner changes it under Settings → Plan & billing (Need more room?), and the extra room counts straight away. A limit that is already unlimited stays unlimited. Prices, how much a unit adds and the Stripe price ids are edited in Admin → Plans → Add-ons. Stripe needs one monthly recurring price per add-on (the price of one unit); the subscription webhook keeps each workspace's quantities in step, and cancelling the plan clears them. Storage costs about $0.03 per GB a month at current cloud prices, so the add-on is a healthy margin; raise the price if your costs rise.
What it costs to run (monthly, approximate, check current prices before relying on them):
| Item | Now | When it grows |
|---|---|---|
| Server (Oracle Always Free VM) | $0 | about $50 to $100 if you outgrow the free ARM allowance |
| Disk and backups | $0 (200 GB free; the Storage card in Admin shows use) | about $0.03 per GB per month beyond that |
| Domain | $0 (DuckDNS) | about $1 (yearly fee spread out) |
| Email (Brevo) | $0 (free daily quota) | about $10 to $25 for a paid tier |
| AI assistance | $0: customers use their own API keys | none |
| CI/CD (GitHub Actions) | $0 within the free minutes | stays $0 (local deploy fallback) |
| Stripe fees | none until a sale | about 3% plus $0.30 per charge, a little more with Stripe Tax: about $5.50 on $149 |
Running costs are near zero today and perhaps $100 to $150 a month once you pay for a bigger server, a domain and email, so one Team customer ($149, about $143 after fees) covers everything. What the table leaves out is yours to add: the business registration and accounting, income tax, and your own time. Break-even on the infrastructure is one customer; break-even on a salary is a number only you can set (at $149 per Team customer, ten customers is about $1,400 a month).
Watch two things as customers arrive: the Storage card (move to a bigger disk before it reaches 80%), and the email quota.
Deleting workspaces that never paid
Off by default. Set DELETE_AFTER_DAYS (for example 60) and, once BILLING_ENABLED is on, the worker deletes a
workspace that is that many days past the end of its unpaid trial, together with its stored backups and files.
Safeguards:
- Only workspaces on the paywall (new sign-ups and admin-granted trials) still in the unpaid
trialingstate. Anything with a Stripe subscription, or a paid status, is never touched. - Never a workspace with Never delete this workspace's data switched on (Admin → Accounts → the workspace), a suspended one, or one containing a platform admin.
- Owners get two emails: 14 days and 3 days before. Deletion happens at least a day after the final warning, and never in the same pass as a warning.
- Each deletion is recorded in the platform audit log (
team.delete.expired, actorsystem). - The trial emails state the deletion period. Choosing a plan at any point stops it.
Before turning it on: put the retention period in the Terms and the sign-up notice. A deleted workspace also stays in older database backups until they rotate out.
Free now, paid later
Diffbridge launches free. With BILLING_ENABLED=false (the default), every workspace gets every
feature with no limits, and the Billing tab says "Free during early access".
All the paid-tier code is already in place. To start charging:
- In Stripe, create a product per paid plan, each with a monthly recurring price. Copy each price id (
price_…). - In Admin → Plans, edit each plan (Free / Pro / Enterprise, or add your own): set the price, the limits and features, and paste the Stripe price id.
- In Stripe, go to Developers → Webhooks and add the endpoint
https://<your-domain>/api/billing/webhookwith these events:checkout.session.completed,customer.subscription.created,customer.subscription.updatedandcustomer.subscription.deleted. Copy the signing secret. - Set these and restart:
BILLING_ENABLED=true STRIPE_SECRET_KEY=sk_live_… STRIPE_WEBHOOK_SECRET=whsec_… - Enable the Customer portal in Stripe's Billing settings, so "Manage billing" can open it.
Once billing is on:
- Every new workspace gets a free trial of
TRIAL_DAYS(default 30) from sign-up: every feature, no limits, no card needed. Workspaces created before billing was turned on have no trial and are never locked automatically; to give one a trial, open Admin → Accounts and set the status to trialing with a trial until date. - After the trial, unpaid, a workspace is read-only. It can still sign in, view and export its data, reach billing and support; every change is refused with a "free trial has ended" message, and automation (CI webhooks and schedules, backups, deployments) stops too. Paying (an active subscription), an Enterprise plan or a plan comped from the admin panel lifts it at once. A platform admin keeps the admin panel even when their own workspace is locked.
- Trial emails go to the workspace owners 7 days before the trial ends, 1 day before, and when it has ended (once each, and only while billing is on). Each links to Plan & billing.
- Limits are enforced when someone adds an org, invites a member, creates a CI job, or starts a deployment (per calendar month). Features (backups, test monitoring, data deploy, pipelines) are checked when they're used.
- Team owners upgrade from Settings → Plan & billing through Stripe Checkout and manage cards and invoices in Stripe's portal.
- Stripe webhooks keep each team's plan and status in sync. They're signature-verified and processed exactly once.
- A canceled or unpaid subscription, or a trial that ended unpaid, puts the team in the read-only state above (the Free plan is the fallback tier for limits, not a way to keep using the product).
Admin panel (/admin)
Only platform admins can see it; everyone else gets a 404. Grant access with
PLATFORM_ADMIN_EMAILS=a@x.com,b@y.com.
| Tab | What you can do |
|---|---|
| Overview | Accounts, users, 30-day signups, active teams, MRR, accounts per plan, whether Stripe and email are configured, and Storage: how full the disk is, the size of stored backups, snapshots and packages, the database size, and the largest workspaces |
| Accounts | Search and filter teams. Open one to change its plan or status, grant a trial until a date, override individual limits (including unlimited), add internal notes, suspend or unsuspend, and see members and orgs. Delete the account (you type its name to confirm) |
| Users | Search everyone, see their sign-in methods (password, Google, GitHub), last login and pending invites, and disable or enable a user, which takes effect immediately |
| Plans | Edit or add plans: price, Stripe price id, limits, features, whether it's public, whether it's active |
| Support inbox | Every support request, suggestion and bug report, filterable by status and type. Reply opens your mail client to the sender. Mark items in progress or resolved |
| Audit log | Every admin action and Stripe-driven change: who did it, what, and when |
A suspended workspace can still sign in, view its data, contact support and reach billing, but every change is blocked until you unsuspend it.
Sign in with Google and GitHub
- Google: in Google Cloud Console, go to APIs & Services → Credentials, create an OAuth client ID of type Web application, and add the authorized redirect URI
https://<your-domain>/api/auth/oauth/google/callback. SetGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET. - GitHub: go to Settings → Developer settings → OAuth Apps → New OAuth App, and set the callback URL to
https://<your-domain>/api/auth/oauth/github/callback. SetGITHUB_CLIENT_IDandGITHUB_CLIENT_SECRET.
The buttons appear on the sign-in page once a provider is configured.
Account merging: when the provider returns a verified email that matches an existing Diffbridge user, the Google or GitHub identity is linked to that user instead of creating a new account. A pending invite is accepted the same way. Unverified provider emails are never merged. Users can also link or unlink providers, and set a password, under Settings → My account.
Contact support, suggestions and bug reports
Help & feedback, in the sidebar or the ⌘K palette, sends a support request, a suggestion or a bug report (with severity, plus the page and browser version if the user allows it). Signed-out users can reach support from the sign-in page.
- Every message is saved to the admin inbox first, so nothing is lost if email fails.
- It's then emailed to
SUPPORT_EMAILwith Reply-To set to the sender, so you can just hit reply. SUPPORT_EMAILis server-only. It never appears in an API response, in the UI or browser bundle, or in the server logs, and it isn't committed to git. A test checks every API response for it.
Email delivery uses one of:
EMAIL_PROVIDER=smtpwithSMTP_HOST,SMTP_PORT,SMTP_SECURE,SMTP_USER,SMTP_PASS. This works with Gmail (use an app password:smtp.gmail.com, port 465, secure), Amazon SES, Postmark and others.EMAIL_PROVIDER=resendwithRESEND_API_KEY.EMAIL_PROVIDER=log(local default): nothing is sent, and the message is still stored in the inbox.