Version
GET

Read a subject's activity

/v1/activity in the Activity API.

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:

curl "https://api.example.test/v1/activity?subject_type=project&subject_id=$PROJECT_ID&limit=20" \  -H "Authorization: Bearer $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, client or project member that belongs to another team returns 404 RESOURCE_NOT_FOUND rather than an empty list; existence never leaks across tenants. A project outside the token's scope:project: allow-list is a 404 for the same reason.

  • subject_type and causer_type use short morph aliases (project, client, project-member, user) rather than internal class names. Treat them as opaque strings. The subject_type query parameter accepts project, client and project-member today, and every artefact alias as its module lands; anything else is 422 VALIDATION_FAILED.
  • actor_kind distinguishes the surface the change came through: human (the app), api_token (REST), mcp (an MCP tool), integration (an inbound delivery such as a Telegram command), webhook, ai (an accepted Heimdall draft) or system (a scheduled job). Filter on it client-side when you need "everything the agent did yesterday" separately from what people did.
  • changes holds, for an update, attributes (the new values) and old (the previous ones) of the columns that changed.
  • 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 a context window never sees credentials that were logged alongside a write.
GET
/v1/activity

Requires ability

The token must hold this ability, or the call is refused with 403.

Runs the same action from an agent, behind the same ability.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted in the app under Account Settings, then API Tokens, sent as Authorization: Bearer zg_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team, and optionally to one project, at mint time.

In: header

Query Parameters

subject_type*ActivitySubjectType

The kind of subject, as a short alias: project, client or project-member. A class name is refused.

Value in

  • "project"
  • "client"
  • "project-member"
  • "component"
  • "environment"
  • "stakeholder"
  • "persona"
  • "glossary-term"
  • "data-entity"
  • "data-field"
  • "design-reference"
  • "repository"
  • "epic"
  • "work-item"
  • "requirement"
  • "business-rule"
  • "use-case"
  • "raid-item"
  • "decision"
subject_id*string

The subject's id.

Formatuuid
limit?integer

How many of the newest entries to return, 1 to 200; defaults to 50. A value above 200 is refused rather than clamped.

Range1 <= value <= 200

Responses

200OK

Array of ActivityResource

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (a zg_test_ token on production).

403Forbidden

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 registered a row answers FORBIDDEN with the same status, and says so in its own description.

404Not 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.

422Validation failed

The payload broke a rule, and error.fields maps each offending key to its messages. A refusal from the domain, such as a role code already taken or a team the caller does not own, 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.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

How is this guide?

Last updated on