---
title: "Read a subject's activity"
method: GET
path: "/v1/activity"
tags: ["Activity"]
---

# Read a subject's activity

`GET /v1/activity`

## Request

- Base URL: `https://api.subscriby.net`
- URL: `https://api.subscriby.net/v1/activity`
- Auth: HTTP bearer

The newest entries recorded against one subject, `limit` at a time (50 by default, 200 at most), newest first. Name the subject by alias and id:

```bash
curl "https://api.subscriby.net/v1/activity?subject_type=project&subject_id=$PROJECT_ID&limit=20" \
  -H "Authorization: Bearer $SUBSCRIBY_TOKEN"
```

There is no paging beyond `limit`: the endpoint is a recent-history read, not an export. The subject is resolved through its own tenant-scoped query before activity is read, so passing the id of a project (or subscription, plan, member) that belongs to another team returns `404 RESOURCE_NOT_FOUND` rather than an empty list; existence never leaks across tenants.

- `subject_type` and `causer_type` use short morph aliases (`project`, `project-subscription`, `project-subscription-plan`, `project-user`, `project-resource`, `user`, …) rather than internal class names. Treat them as opaque strings. The `subject_type` **query parameter** accepts only the aliases listed on the endpoint; a class name is `422 VALIDATION_FAILED`.
- `actor_kind` distinguishes the surface the change came through: `human` (dashboard click), `api_token` (REST), `mcp` (MCP tool), `zapier`, `webhook`, `system` (scheduled job). Filter on it client-side when you need "everything the agent did yesterday" separately from dashboard clicks.
- `properties` keys matching `token`, `secret`, `password`, `api_key` or `api_secret` (case-insensitive) are stripped at any depth before the response leaves the server, so LLM context windows never see credentials that were logged alongside a write.

## Query parameters

- `subject_type` 'project' | 'subscription' | 'project-subscription' | 'member' | 'project-user' | 'plan' | 'project-subscription-plan' | 'access-code' | 'coupon' | 'project-resource' | 'referral-program' | 'referral-affiliate' | 'smart-link' | 'sequence', required: The subjects the public activity surfaces may be asked about. The alias is the contract, not the class name: the REST endpoint used to accept any model FQCN as a fallback, which let a caller probe for class names and pointed a user-controlled string at `::query()`. Only these aliases resolve now, and each names the one model it stands for. Two vocabularies are accepted because two surfaces documented them. The REST endpoint has always said `member`, `subscription` and `plan`; the MCP tool has always said `project-user`, `project-subscription` and `project-subscription-plan`. Both map to the same model, so an agent written against either keeps working. | | |---| | `project` <br/> | | `subscription` <br/> | | `project-subscription` <br/> The MCP spelling of a subscription. | | `member` <br/> | | `project-user` <br/> The MCP spelling of a member. | | `plan` <br/> | | `project-subscription-plan` <br/> The MCP spelling of a plan. | | `access-code` <br/> An access code is a pending subscription row, so its history lives under the subscription model. | | `coupon` <br/> | | `project-resource` <br/> | | `referral-program` <br/> | | `referral-affiliate` <br/> | | `smart-link` <br/> | | `sequence` <br/> |
- `subject_id` string, uuid, required
- `limit` integer

## Response `200`

Array of `ActivityResource`

- object
  - `data` ActivityResource[], required: The items.
    - `id` string, required: The entry's id.
    - `log_name` string, nullable, required: The log the entry was written to; `default` for every application entry.
    - `description` string, required: What happened, in the recorder's words, such as `created` or `updated`.
    - `event` string, nullable, required: The lifecycle event the entry records: `created`, `updated`, `deleted` or `restored`; null for a manual entry.
    - `subject_type` string, nullable, required: The kind of thing that changed, as a short alias such as `project`, `project-subscription`, `project-subscription-plan`, `project-user` or `project-resource`. Treat it as an opaque string.
    - `subject_id` string, nullable, required: The id of the thing that changed.
    - `causer_type` string, nullable, required: The kind of actor, as a short alias such as `user`; null for a system change.
    - `causer_id` string, nullable, required: The actor's id; null for a system change.
    - `actor_kind` string, nullable, required: The surface the change came through: `human` (dashboard), `api_token` (REST), `mcp` (an MCP tool), `zapier`, `webhook` or `system` (a scheduled job). Filter on it client-side to separate what an agent did from dashboard clicks.
    - `properties` object, required: What was recorded with the change, typically `attributes` (the new values) and `old` (the previous ones). Keys matching `token`, `secret`, `password`, `api_key` or `api_secret`, at any depth and in any case, are stripped before the response leaves the server.
    - `created_at` string, nullable, required: When the change was recorded, ISO 8601.

## Other responses

- `401`: `AUTHENTICATION_REQUIRED`: the request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an `sbt_test_` token on production).
- `403`: `TOKEN_MISSING_ABILITY`: the token is valid but does not carry the ability this endpoint requires; `error.context.required_ability` names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers `FORBIDDEN`, `TEAM_TIER_REQUIRED` or `CONNECTOR_TIER_REQUIRED` with the same status, and says so in its own description.
- `404`: `RESOURCE_NOT_FOUND`: when the subject does not exist in the caller's tenant, or belongs to a project outside the token's `scope:project:` allow-list.
- `422`: `VALIDATION_FAILED`: the payload broke a rule, and `error.fields` maps each offending key to its messages. A refusal from the domain, such as a plan that cannot go on sale or a member who cannot be removed, uses the same code with `error.message` saying why and no `fields`. On this endpoint: `VALIDATION_FAILED`: when `subject_type` or `subject_id` is missing, the alias is unknown, the id is not a UUID, or `limit` is above 200.
- `429`: `RATE_LIMITED`: the token has spent its 300 requests a minute or 10,000 an hour; `Retry-After` says when the next one is accepted.

---

[API](https://skmtc.dev/memberpass/apis/subscriby-rest-api.md) · [All operations](https://skmtc.dev/memberpass/apis/subscriby-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/memberpass/apis/subscriby-rest-api/revisions/59c4df91d764?raw)
