Settings → Billing
Purpose
Manage a clinic's CS Logbook subscription.
Each clinic has its own subscription. If you own three clinics, each one subscribes separately, and each clinic's billing page shows only that clinic's subscription. There is no personal subscription that covers several clinics.
CFR tie: none (operational concern, not a regulatory requirement). Subscription state does, however, gate functional access via RLS: every domain table's INSERT / UPDATE policy includes has_active_subscription(account_id), and the read policies use the read-tier variant has_active_or_grace_subscription(account_id). Both look only at the clinic's own subscription.
When to use it
- First subscription: subscribe a clinic after creating it
- Update payment method: card on file expired or changed
- Cancel: end the clinic's subscription (records stay readable and exportable for 90 days after cancellation)
Walkthrough
Step 1: Open the billing page
Open the clinic, then choose Billing in the clinic's sidebar (/home/<slug>/billing). The item
appears for members who can manage billing.
A clinic without an active subscription is sent to this page when you open it.
The page shows the clinic's current plan (if subscribed) or the plan selector (if not).

Step 2: Select a plan (initial subscription)
Click a plan card (data-test-plan attribute on each). Click Proceed to checkout (data-test="checkout-submit-button").
You'll be redirected to the Stripe Checkout flow: a Stripe-hosted (or embedded-iframe) page where you enter your credit card and billing details.
(Stripe checkout boundary screenshot intentionally not captured by 15g: the iframe is JS-protected by Stripe and Playwright cannot drive it. Existing canonical coverage is apps/e2e/tests/team-billing/team-billing.spec.ts. The Sprint A verification records record this as the OPEN / UNVERIFIED close-out per .claude/rules/verification-discipline.md § 4.)
After successful payment, Stripe redirects back to /home/<slug>/billing/return. The CS Logbook return page polls for the webhook to confirm the subscription is active.
Step 3: Manage subscription (after subscribing)
Once subscribed, the page shows a Manage Billing button (data-test="manage-billing-redirect-button"). Click it to be redirected to the Stripe customer portal: the portal is where you change payment method, download invoices, change plan, or cancel.
Step 4: Cancel
Inside the portal, select Cancel subscription. CS Logbook receives the cancellation webhook and marks the subscription as canceled at the period end. Read and export access continues for 90 days after cancellation (has_active_or_grace_subscription); write access ends at period end.
Step 5: Subscribe again after canceling
Once a canceled subscription has ended, the billing page shows the plan picker again, below a note about the previous subscription. Choose a plan and click Proceed to checkout to start a new subscription.
- No second free trial. A clinic's trial is offered once, so a returning subscriber is charged from the start.
- The clinic's Stripe customer is reused. Saved payment details and past invoices stay in the same billing portal.
- Checkout stays closed while a subscription is still running or a payment is overdue. Use Manage Billing to update the payment method instead; a second subscription would bill the clinic twice.
- A payment in progress also keeps checkout closed. If a first payment is still being confirmed, the page says so, and checkout opens again once that payment completes or expires (within 23 hours).
Field reference
Plan
| Plan | Price | Trial |
|---|---|---|
| CS Logbook Online | $50/month or $500/year per clinic | Offered once per clinic |
CS Logbook Online is the only plan. CS Logbook Sheets Edition was discontinued on 2026-08-06 and cannot be purchased; if you are reading an older guide that lists it, that guide is out of date.
The paid plan has no user limit and no metered storage or overage.
(Source: ADR-057 and ADR-065.)
Subscription state
subscriptions table columns (MakerKit standard, not user-facing):
status:trialing/active/past_due/canceled/unpaidperiod_starts_at/period_ends_atcancel_at_period_end(boolean)
has_active_subscription(account_id) returns true for status IN ('active', 'trialing') on the clinic's own subscription.
has_active_or_grace_subscription(account_id) returns true when has_active_subscription does, when the clinic's subscription is past_due, unpaid or paused, or when it was canceled within the last 90 days. incomplete and incomplete_expired grant no access of their own.
Edge cases
Subscription state gates RLS
Most domain tables' INSERT / UPDATE policies require has_active_subscription(account_id). If a payment fails, or the subscription is paused, you can still read and export the clinic's records, but you cannot add or change records until billing is updated. After a cancellation, read and export continue for 90 days.
Trial-to-paid transition
The first checkout converts trial → paid via the Stripe webhook. The clinic should not see write-blocking during the transition: trialing status satisfies has_active_subscription.
Webhook timing
Subscription state updates are webhook-driven. If the webhook is slow, the user may see "no active subscription" for a few seconds after returning from Stripe. The return page polls for ~10 seconds; refreshing usually resolves any UI lag.
Stripe customer portal vs. CS Logbook UI
Payment method updates, invoice downloads, and cancellation all happen in the Stripe customer portal, not in CS Logbook. CS Logbook is the entry point.
Billing emails
Renewal, payment and cancellation emails for a clinic's subscription go to the clinic's owner and link to that clinic's billing page.
Common mistakes
- Cancelling without exporting first. After cancellation your records are read-only, and read and export access ends 90 days later. Run Settings → Data Export BEFORE cancellation.
- Expecting one subscription to cover several clinics. Each clinic subscribes on its own billing page.
- Confusing test mode with prod. Stripe test cards (the canonical
4242…Visa test number documented at https://stripe.com/docs/testing) work in dev but never in prod. If you see "test card" errors, you're in production with a test card by mistake. - Treating the Manage Billing redirect as a UX bug. The redirect to the Stripe portal is intentional: Stripe is the payment / invoicing source of truth; CS Logbook does not duplicate that surface.
Related
- Existing e2e coverage:
apps/e2e/tests/team-billing/team-billing.spec.tsexercises the Stripe checkout flow against the test harness - Settings → Data Export: export records before cancellation
- Settings → Members
- Glossary § Subscription gating