---
title: "Platform activity feed"
method: GET
path: "/stats/activity"
tags: ["Stats"]
---

# Platform activity feed

`GET /stats/activity`

## Request

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

Admin-only reverse-chronological timeline of noteworthy platform actions (signups, site creates/publishes, plan changes, cancellations, deletions, settings changes, …). Keyset-paginated: pass the returned `nextCursor` back as `cursor` to load older entries. Filter by coarse `categories` (growth/revenue/churn/ops) and/or explicit `types`, which are unioned.

## Query parameters

- `categories` string[]
- `types` string[]
- `siteId` string, uuid
- `actorUserId` string, uuid
- `limit` number
- `cursor` string

## Response `200`

- APIActivityFeed
  - `items` APIActivityEvent[], required
    - `id` string, required: Event id (UUID).
    - `type` 'user.signed_up' | 'site.created' | 'site.published' | 'organization.created' | 'subscription.started' | 'subscription.plan_changed' | 'subscription.canceled' | 'subscription.cancel_scheduled' | 'subscription.cancel_reverted' | 'subscription.payment_failed' | 'plan.limit_hit' | 'preview.published' | 'preview.updated' | 'preview.discarded' | 'preview.promoted' | 'preview.update_refused' | 'site.deleted' | 'account.deleted' | 'member.left' | 'site.settings_changed' | 'site.suspended' | 'site.restored' | 'site.renewed' | 'site.restored_from_trash' | 'site.purged' | 'custom_domain.added' | 'custom_domain.verified' | 'member.invited' | 'member.joined' | 'user.role_changed' | 'form.replies_revealed' | 'user.banned' | 'user.unbanned' | 'signup.blocked' | 'email_domain.added' | 'email_domain.removed' | 'risk.flagged' | 'risk.cluster_reviewed' | 'risk.cluster_review_removed' | 'risk.user_trusted' | 'risk.user_trust_removed' | 'signup_allowlist.added' | 'signup_allowlist.removed' | 'duplicate.case_opened' | 'evidence.case_opened' | 'evidence.link_created' | 'evidence.link_revoked' | 'duplicate.reminder_sent' | 'duplicate.combine_requested' | 'duplicate.account_combined' | 'duplicate.account_deleted' | 'duplicate.case_disputed' | 'duplicate.case_resolved' | 'duplicate.case_released' | 'email.sent', required: What happened.
    - `category` 'growth' | 'revenue' | 'churn' | 'ops', required: Coarse bucket this event belongs to (derived from `type`).
    - `subjectType` 'user' | 'site' | 'account' | 'subscription' | 'custom_domain' | 'membership' | 'preview' | 'email_domain_rule' | 'signup_allowlist' | 'risk_review' | 'duplicate_case' | 'evidence_case', required: The kind of entity this event is about.
    - `subjectId` string, nullable, required: Id of the subject entity — null if not applicable.
    - `actorUserId` string, nullable, required: User who performed the action — null for system events.
    - `accountId` string, nullable, required: Owning account (tenancy boundary) — null if not applicable.
    - `siteId` string, nullable, required: Related site — null if the event is not about a site.
    - `platform` 'web' | 'cli' | 'mcp' | 'extension' | 'api', nullable, required: Client surface the action came from (web dashboard, CLI, MCP server, browser extension, or a generic API-token client). Null for events with no originating request (webhooks, crons) and for rows that predate platform recording.
    - `metadata` object, required: Denormalized display fields captured at write time (subdomain, account name, plan from→to, which setting changed, …). Shape depends on `type`.
    - `createdAt` string, required: When the event occurred (ISO 8601).
  - `nextCursor` string, nullable, required: Cursor for the next (older) page, or null when there are no more rows.

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