Skip to main content

Billing

The Billing admin view is an at-a-glance dashboard of plan distribution and active subscriptions. It does not manage individual Stripe subscriptions, refunds, or manual overrides — those actions are still performed inside the Stripe Dashboard. This page is a monitoring surface only, with deeper subscription and coupon tooling living on dedicated admin pages.

Where to find it

The page lives at /billing. It has no sidebar entry — navigate to it directly, or reach billing work through Coupons, Subscriptions, and Plans, which are all in the sidebar's Commerce section.

Quick start

  1. Open /billing.
  2. Scan the KPI cards at the top for total / free / pro / enterprise account counts.
  3. Read the Subscriptions card for a count of active Stripe subscriptions and a link reminder that Stripe Dashboard is the source of truth for details.
  4. For coupon work, jump to Coupons.
  5. For plan-level configuration, jump to Plans.

Detailed walkthrough

KPI grid

Four KPI cards:

  • Total Accounts — every account in the system.
  • Free Accounts — accounts on the free plan slug.
  • Pro Accounts — accounts on the pro plan slug.
  • Enterprise Accounts — a leftover tile from the dropped enterprise tier (removed by migration 20260415000009_drop_enterprise_plan). It has no accounts behind it.

The page is a server component (page.tsx is async) and renders counts via a getPlanStats() helper. That helper returns hard-coded zeros — it is not wired to the admin API — so every card reads 0. The translations and layout are final.

Subscriptions card

A single card titled Subscriptions shows:

  • "{count} active subscriptions" — a read-only count.
  • A static footnote: "Detailed subscription management is available in the Stripe Dashboard."

There are no buttons, no refund flow, and no manual subscription editing here.

Coming-soon banner

apps/admin/messages/\{en,de\}.json carries billing.comingSoon and billing.comingSoonDescription copy for a richer billing view. Neither string is rendered by the shipped page.

Common scenarios

  • "How many paying customers do we have right now?" — the Pro KPI reads 0 regardless; count Pro badges on the Subscriptions or Accounts list instead.
  • Refund / cancel a subscription — not possible here. Go to Stripe Dashboard.
  • Apply a manual coupon to an account — use Coupons to create the coupon, then apply it from the Stripe customer record.
  • Override a plan without Stripe — use Accounts → Plan Management and Limits. That change is independent of Stripe.

Permissions

ActionPermission
Open the billing pagebilling:read

Entry also requires admin:access. System admins have this implicitly.

billing:edit exists in the admin permission registry but no endpoint or UI element enforces it today.

API

There is no dedicated billing analytics endpoint. When getPlanStats() is wired up it will aggregate the admin accounts listing.

UI actionGraphQLREST
Count accounts by planadminAccountsGET /v1/admin/accounts

For end-user billing actions (checkout, portal, cancel, invoices), see the non-admin billing REST endpoints in apps/api/src/routes/billing.rs:

  • POST /v1/billing/checkout
  • POST /v1/billing/portal
  • GET /v1/billing/status
  • POST /v1/billing/cancel
  • GET /v1/billing/invoices
  • GET /v1/billing/validate-coupon
  • POST /v1/webhooks/stripe

These are not admin-scoped — they act on the authenticated user's own subscription.

Tips & gotchas

  • KPIs read zero — getPlanStats() returns constants. Don't treat the numbers on this page as data.
  • Stripe is the source of truth. Manual DB edits here will drift out of sync with Stripe webhooks.
  • There is no manual-override or refund UI today. If you need one, file an issue — there are currently no hidden admin flows for it.
  • Coupons — discount codes issued to Stripe
  • Subscriptions — per-account subscription overview
  • Plans — plan definition and feature grid
  • Accounts — per-account plan override (independent of Stripe)