---
title: "User drill-down (memberships + sites)"
method: GET
path: "/stats/users/{id}"
tags: ["Stats"]
---

# User drill-down (memberships + sites)

`GET /stats/users/{id}`

## Request

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

Admin-only detail for one user: the enriched directory row, every account membership (any status) with account name/kind and plan, and the sites across accounts where the user has an active membership (newest first, capped at 100). The user’s activity timeline is served separately by `GET /stats/activity?actorUserId=`.

## Path parameters

- `id` string, required

## Response `200`

- APIAdminUserDetail
  - `user` APIAdminUser, required
    - `id` string, required: User id (UUID).
    - `name` string, required: Display name.
    - `email` string, required: Email address.
    - `emailVerified` boolean, required: Whether the email address is verified.
    - `role` 'user' | 'admin', required: Platform role.
    - `createdAt` string, required: Sign-up time (ISO 8601).
    - `accountsCount` number, required: Number of accounts the user has an active membership in.
    - `sitesCount` number, required: Number of sites across the accounts the user has an active membership in.
    - `plan` 'free' | 'basic' | 'pro' | 'max', required: Highest plan tier across the subscriptions of the accounts the user has an active membership in (`free` when none).
    - `lastActiveAt` string, nullable, required: Time of the user’s most recent activity event (ISO 8601) — null if they have never acted.
    - `signupRef` string, nullable, required: The `ref` slug the user signed up with (acquisition channel); null for an unattributed signup.
    - `marketingOptOut` boolean, required: Whether the user opted out of lifecycle and marketing email.
    - `bannedAt` string, nullable, required: When an admin banned the user (ISO 8601); null if not banned.
    - `bannedReason` string, nullable, required: The reason the admin gave for the ban; null if not banned.
    - `bannedByName` string, nullable, required: Display name of the admin who applied the ban; null if not banned or that admin no longer exists.
    - `riskScore` number, nullable, required: Advisory risk score (0–100) from the last recompute; null when the user is not flagged (ADR 0049).
    - `riskLevel` 'high' | 'medium' | 'low', nullable, required: Advisory risk level; null when not flagged.
    - `riskReviewed` boolean, required: True while an admin review marks the user’s cluster as not a problem (ADR 0055). The score stays; the risk filters skip the user.
  - `memberships` APIAdminUserMembership[], required: All memberships (any status), oldest first.
    - `accountId` string, required: Account id (UUID).
    - `accountName` string, nullable, required: Account display name — null if the account no longer exists.
    - `accountKind` 'personal' | 'organization', nullable, required: Account kind — null if the account no longer exists.
    - `role` 'owner' | 'admin' | 'member', required: The user’s role in the account.
    - `status` 'invited' | 'active' | 'suspended', required: Membership status.
    - `plan` 'free' | 'basic' | 'pro' | 'max', required: The account subscription’s plan tier (`free` when none).
    - `joinedAt` string, nullable, required: When the user joined the account (ISO 8601) — null while the invitation is outstanding.
    - `subscriptionStatus` 'active' | 'trialing' | 'past_due' | 'canceled' | 'incomplete' | 'incomplete_expired' | 'unpaid' | 'paused', nullable, required: State of the account subscription; null when the account has no subscription row.
    - `billingInterval` 'month' | 'year', nullable, required: Billing interval of the subscription; null when none.
    - `currentPeriodEnd` string, nullable, required: End of the current billing period or trial (ISO 8601); null when the account never subscribed.
    - `cancelAtPeriodEnd` boolean, required: Whether the subscription is cancelled and ends with the current period.
    - `stripeCustomerId` string, nullable, required: Stripe customer id of the account, for a link to the Stripe dashboard; null when the account never reached checkout.
  - `sites` APIAdminUserSite[], required: Sites across accounts with an active membership, newest first, capped.
    - `id` string, required: Site id (UUID).
    - `subdomain` string, required: Site subdomain.
    - `url` string, required: Public URL of the site.
    - `status` 'pending' | 'awaiting_verification' | 'live' | 'inactive' | 'suspended', required: Site lifecycle status.
    - `createdAt` string, required: Creation time (ISO 8601).
  - `tokens` APIAdminUserToken[], required: API and MCP tokens the user created, newest first, capped.
    - `id` string, required: Token id (UUID).
    - `name` string, required: The name the user gave the token.
    - `displayPrefix` string, required: Non-secret display prefix of the token.
    - `scopes` string[], required: Granted scopes.
    - `createdVia` string, nullable, required: How the token was created: a `ref` slug or `oauth:<client>`; null for a token made on the dashboard.
    - `accountName` string, nullable, required: Name of the account the token acts on; null if deleted.
    - `createdAt` string, required: Creation time (ISO 8601).
    - `lastUsedAt` string, nullable, required: Last use (ISO 8601); null when never used.
    - `expiresAt` string, nullable, required: Expiry (ISO 8601); null when the token does not expire.
    - `revokedAt` string, nullable, required: Revocation time (ISO 8601); null while the token works.

## Other responses

- `403`: Admin access required
- `404`: User not found

---

[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)
