The sixth and final Dashboard Guide page. This page is about the plan/subscription side specifically — for what actually counts as an MAU and how it's measured, see Monitoring → Usage; this page doesn't repeat that.
Four tiers, matching lib/config/plans.ts exactly — no drift between the marketing copy and the real enforced limits:
The page itself shows: a Current Plan card (name, price, a static per-tier description, an Upgrade button, and — Scale only — a "Talk to Enterprise" link); a Billing Info card that differs by tier (Free shows a flat "no billing" note; paid tiers show next billing date, current charge, and a link to Contact Support to manage the subscription — there's no self-service cancel here); a Plan Limits grid (MAU, environments, rate limit, support tier) that color-escalates the same way Overview and Usage do once you're near or past your limit; and Invoice History, pulled live from Razorpay, when any invoices exist.
Worth being precise about, since it's easy to misread the page too optimistically: paid tiers do show a real per-MAU overage rate (Starter $0.008, Growth $0.006, Scale $0.004 — these are real, configured numbers, not placeholders). But the rate is displayed with a "Coming Soon" pill right next to it, and any estimated overage amount computed on the page is explicitly labeled "not charged this cycle." Free plan shows a plain "Coming Soon" placeholder instead of a number at all. The plain fact: nobody is actually billed for overage today, on any tier. The numbers are real and will presumably apply once this ships — they just aren't live yet.
This is worth stating factually rather than vaguely, since the difference matters a lot to anyone reading this page hoping to actually pay: I checked the real environment configuration directly. RAZORPAY_KEY_ID and NEXT_PUBLIC_RAZORPAY_KEY_ID are both genuine Razorpay test-mode credentials (rzp_test_… — not rzp_live_…).
What that means practically: clicking "Select Plan" for Starter, Growth, or Scale is fully real, wired code — it calls a real backend route that creates an actual Razorpay customer and subscription object, then opens Razorpay's real Checkout widget. None of that is mocked. But every part of it runs against Razorpay's test/sandbox environment. You can click through the entire upgrade flow today and it will genuinely work end to end as a test — you just can't complete a real payment or actually unlock a paid tier through it right now, because it isn't connected to Razorpay in live mode. This page is testable, not yet usable for real billing.
Separately, and regardless of test/live status: downgrading isn't self-service at all. The upgrade modal disables the button for any tier below your current one (labeled "Downgrade" but non-functional) and points you to Contact Support instead — that's the only real path to move to a lower tier or cancel, today.
This isn't just a UI convention. Two independent checks, confirmed directly in the code:
POST /api/developer/billing/subscribe — independently re-checks the caller's real role column from the database server-side (requireOwner()) and rejects anyone who isn't an Owner, regardless of what the UI shows them. A Member calling this endpoint directly, bypassing the hidden nav item entirely, would still be rejected.One honest asymmetry worth noting: the read-only endpoints behind this page (fetching the subscription portal info and invoice history) only require being signed in as any team member, not specifically an Owner — so the owner-only protection is specifically on the thing that costs money, not on viewing billing history in principle. In practice a Member can't reach this page at all, since the nav item is hidden.
This completes the six-page Dashboard Guide. For the consumption side of this same picture — real MAU numbers, the login method breakdown, and the authentication funnel — see Monitoring.