---
title: "Site directory with per-site stats"
method: GET
path: "/stats/sites"
tags: ["Stats"]
---

# Site directory with per-site stats

`GET /stats/sites`

## Request

- Base URL: `https://api.nippy.host`
- URL: `https://api.nippy.host/stats/sites`
- Auth: `bearer` (a scheme the document does not define)

Admin-only site directory, offset-paged via `page` + `pageSize` and sorted server-side (across every matching site, not just the returned page) via `sortBy` + `sortDir` — defaults to newest-created first. Each row carries the owning account name + email, owner user id + plan, content stats, and trailing-30-day traffic and a daily pageview sparkline. Optionally filtered by status and by a `search` term (subdomain, owner email, account name or custom hostname); `total`/`totalPages` reflect the filters. Row-level and names the owning account, so admin-only. Served from a short server-side cache (keyed per filter + sort + page).

## Query parameters

- `status` 'live' | 'inactive' | 'suspended' | 'awaiting_verification'
- `search` string
- `page` number
- `pageSize` number
- `sortBy` 'created' | 'pageviews' | 'visitors' | 'lastPublished'
- `sortDir` 'asc' | 'desc'

## Response `200`

- APIStatsSites
  - `sites` APIStatsSite[], required
    - `id` string, required: Site id (UUID).
    - `subdomain` string, required: Subdomain on the platform apex.
    - `url` string, required: Public URL the site is served at.
    - `status` 'pending' | 'awaiting_verification' | 'live' | 'inactive' | 'suspended', required: Lifecycle status of the site.
    - `createdAt` string, required: When the site was created (ISO 8601).
    - `lastPublishedAt` string, nullable, required: When the site was last published (most recent finalized upload), ISO 8601 — null if it has never published.
    - `fileCount` number, nullable, required: Files currently hosted (most recent finalized version) — null if the site has never published.
    - `totalBytes` number, nullable, required: Bytes currently stored (most recent finalized version) — null if the site has never published.
    - `pageviews` number, required: Sample-corrected pageviews over the trailing window.
    - `bytesServed` number, required: Sample-corrected bytes served over the trailing window.
    - `visitors` number, required: Distinct visitors over the trailing window.
    - `viewsSeries` number[], required: Daily pageviews over the trailing window, oldest first — exactly `windowDays` zero-filled buckets. Powers the per-row sparkline.
    - `ownerName` string, nullable, required: Name of the owning account — null if the account is missing.
    - `ownerEmail` string, nullable, required: Email of the owning account's owner membership — null when the account has no bound owner membership.
    - `ownerUserId` string, nullable, required: User id of the owning account's owner membership — links the directory to the admin user drill-down. Null when the account has no bound owner membership.
    - `ownerRiskLevel` 'high' | 'medium' | 'low', nullable, required: Advisory risk level of the owner (ADR 0049); null when not flagged, or when an admin reviewed the owner’s cluster as not a problem.
    - `plan` 'free' | 'basic' | 'pro' | 'max', required: Plan tier of the owning account (defaults to free).
  - `total` number, required: Total number of sites matching the status filter.
  - `page` number, required: 1-based page number this response covers.
  - `pageSize` number, required: Rows per page used for this response.
  - `totalPages` number, required: Total number of pages at this page size (always ≥ 1).
  - `windowDays` number, required: Trailing window the traffic figures and sparkline cover.

## Other responses

- `403`: Admin access required

---

[API](https://skmtc.dev/nippy/apis/nippy-backend-api.md) · [All operations](https://skmtc.dev/nippy/apis/nippy-backend-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nippy/apis/nippy-backend-api/revisions/7ab23f040a55?raw)
