Build SaaS Billing + Tax Core on nextjs-prisma-postgres
Production Stripe Billing core for a seat-based SaaS — plans, seats, proration, dunning, idempotent webhooks, Stripe Tax, invoices, customer portal — as a receipt-backed build pack for your own coding agent.
This build pack is pinned for nextjs-prisma-postgres, with verification pending. No pass rate is published until the harness runs it.
nextjs-prisma-postgres versions lock
| node | 24.18.1 |
| next | 16.2.12 |
| react | 19.2.8 |
| react-dom | 19.2.8 |
| stripe | 22.3.0 |
| stripe-api-version | 2026-06-24.dahlia |
| prisma | 7.9.1 |
| @prisma/client | 7.9.1 |
| @prisma/adapter-pg | 7.9.1 |
| typescript | 5.9.3 |
| vitest | 4.1.10 |
| tailwindcss | 4.3.3 |
| @tailwindcss/postcss | 4.3.3 |
| shadcn | 4.13.1 |
| tailwind-merge | 3.6.0 |
| clsx | 2.1.1 |
| class-variance-authority | 0.7.1 |
| @types/node | 24.3.0 |
| @types/react | 19.2.2 |
| @types/react-dom | 19.2.2 |
| postgres | 17.10 |
What you get
A running Next.js service that is the complete billing spine of a seat-based B2B SaaS, with Stripe as the system of record.
**Features**
- Plan catalog (flat + per-seat tiers), synced to Stripe Products/Prices by an idempotent setup script keyed on `lookup_key` — no hardcoded price IDs anywhere.
- Subscribe via hosted Stripe Checkout with Stripe Tax: automatic tax calculation, B2B tax-ID collection (reverse charge), required billing address.
- Seats: add seats now (prorated, charged immediately), remove seats at renewal (never mid-cycle refunds), guarded against dropping below seats in use or above plan max.
- Plan changes: upgrades apply and invoice immediately (`always_invoice`, payment failure blocks the upgrade); downgrades apply at period end via a two-phase subscription schedule.
- Dunning: webhook-driven billing state machine with a 14-day read-only grace window computed at request time — no cron, no drift; Stripe Smart Retries does payment recovery.
- Webhooks: signature-verified, DB-enforced idempotent, out-of-order-safe processor for a deliberately minimal event set — including churn-and-return (a returning customer's new subscription cleanly replaces the canceled one). Honest limit: Stripe's `event.created` has 1-second resolution, so two distinct events inside the same second apply last-writer-wins; a same-second inversion cannot corrupt Stripe (the local row is a display/entitlement cache) and self-heals on the next subscription event.
- Invoices: history from Stripe with hosted PDF links (nothing stored locally).
- Customer portal: payment-method update, invoice history, cancel-at-period-end — plan switching deliberately disabled so your proration policy stays enforced in code.
- Acceptance suite + `verify.sh`: 16 receipt-grade checks (including network-free behavior probes of every billing route), exit 0 = correct build.
- Ops runbook for everything code can't do: Smart Retries settings, tax registrations, webhook endpoint, live smoke test.
**Screens / surfaces**
- `/billing` — plan, seat count with change controls, billing-state banner (active / read-only grace / blocked), invoice list, portal button (Tailwind 4 + shadcn/ui, pinned).
- Stripe-hosted Checkout (tax, tax IDs, addresses handled by Stripe).
- Stripe-hosted customer portal (restricted feature set).
- API: `POST /api/billing/{checkout,plan,seats,portal}`, `GET /api/billing/invoices`, `POST /api/stripe/webhook`.
Prescribed services
Disclosure: some links on this page are affiliate links. We may earn a commission if you sign up through them, at no extra cost to you. We only link to services the pack actually verified against.