Platform operators

Admin overview

Platform operatorsAdmin overview

The admin overview lives at https://booking.netwit.ca/admin. After you sign in, this is the first page you land on. It is meant to answer one question fast: is the platform healthy and is revenue growing?

Top-of-page KPIs

Four cards, computed live from GET /api/admin/stats:

KPIWhat it countsSource
TenantsAll-time count of rows in tenantsSELECT COUNT(*) FROM tenants
UsersOwners + staff across all tenantsSELECT COUNT(*) FROM users
Bookings (30d)Bookings created in the last 30 days; subtitle shows all-time totalcreated_at >= now-30d
GMV (30d)Sum of successful payment amounts in the last 30 days; subtitle shows paying tenant countpayments WHERE status='succeeded' AND created_at >= now-30d
MRR is a derived number, not a stored field.
The endpoint does not return MRR directly. MRR is computed client-side as the count of tenants with plan = 'pro' × $29 (plus any Enterprise contracts tracked manually in the Plans and billing page). Read the Plans and billing guide for the exact formula.

Response shape

{
  "data": {
    "totals": {
      "tenants": 124,
      "users": 312,
      "customers": 4821,
      "bookings": 9876,
      "recentBookings30d": 1184,
      "payingTenants30d": 47,
      "gmv30d": 68420
    },
    "signupsByDay": [
      { "day": "2026-07-19", "c": 3 },
      { "day": "2026-07-20", "c": 5 },
      { "day": "2026-07-21", "c": 2 }
    ]
  }
}

Charts

The overview page renders three charts from the stats response:

  • Tenant growth (7 days) — a bar chart of signupsByDay. If you see a flat week, check whether the marketing site is up and the signup form is reachable.
  • Bookings over time (30 days) — derived client-side from recentBookings30d and a same-period comparison. The current build only shows the 30d total; a per-day series is on the roadmap.
  • Revenue by plan (30 days) — bar chart bucketing gmv30d by tenant plan. Free tenants contribute zero to GMV. Pro and Enterprise tenants are the only contributors.

Recent activity

Below the charts, the page lists the five most recent tenants with their plan, signup time, and a link to the full record. The Recent tenants panel pulls GET /api/admin/tenants?limit=5 and renders the same row shape used by the tenants list.

Two pieces of activity are not yet surfaced on the overview but are available elsewhere:

  • Latest churn — there is no automatic "churn" event in the platform today. A tenant is "churned" when its is_active = 0 or its plan is manually downgraded from pro to free. Use the audit log filtered by tenant.plan_changed to find the latest ones.
  • Latest support tickets — BookFlow does not yet run an in-app ticketing system. Tickets arrive by email to hello@netwit.ca and are tracked in the shared support inbox, not in this overview.

Refresh cadence

The overview polls the API every 30 seconds while the tab is visible. There is no push or websocket in the current build — if you need a real-time number (e.g. during a launch, or while a tenant is upgrading), refresh the page manually.

API

GET/api/admin/stats

Platform-wide totals (tenants, users, customers, bookings, recentBookings30d, payingTenants30d, gmv30d) plus a 7-day signup series. Requires a super_admin JWT.

Sample call

curl https://booking-api.netwit.ca/api/admin/stats \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Response

{
  "data": {
    "totals": {
      "tenants": 124,
      "users": 312,
      "customers": 4821,
      "bookings": 9876,
      "recentBookings30d": 1184,
      "payingTenants30d": 47,
      "gmv30d": 68420
    },
    "signupsByDay": [
      { "day": "2026-07-19", "c": 3 }
    ]
  }
}

Field reference

totals.tenantsinteger

All-time count of rows in the tenants table. Includes suspended and deleted tenants.

totals.usersinteger

All-time count of rows in users (owners + staff). Does not include customer accounts.

totals.customersinteger

All-time count of rows in customers (the per-tenant customer profile table).

totals.bookingsinteger

All-time count of rows in bookings, regardless of status.

totals.recentBookings30dinteger

Bookings with created_at >= now-30d. Status-agnostic.

totals.payingTenants30dinteger

COUNT(DISTINCT tenant_id) of payments with status='succeeded' in the last 30 days.

totals.gmv30dinteger

Sum of amount (in minor units — cents) for successful payments in the last 30 days.

signupsByDayarray

One row per day for the last 7 days: {`day: "YYYY-MM-DD", c: number`}. Sorted ascending by day. Days with zero signups are not included.

What this page does not do

  • It does not show system health — that's the System health page.
  • It does not show audit log entries — that's the Audit log page.
  • It does not let you take action on a tenant. To suspend, restore, or change a plan, open the tenant's detail page.
Need a human?

Email hello@netwit.ca or call +1-604-206-8169. NetWit responds in 1 business day.