Account activity
Every mutating action on an account is recorded with the person who did it, what it touched, and when. The dashboard shows the feed under Account → Activity; the same data is available at GET /v1/account/events.
This is the record for questions like who deleted that Cell and when did that vault key change — and, on a shared account, which of us did it.
What is recorded
| Action | Written when |
|---|---|
member.invited |
Someone is invited to the account |
member.invite_revoked |
An open invite is withdrawn |
member.joined |
An invite is accepted and the person joins |
member.role_changed |
A member moves between admin and member |
member.removed |
A member is removed, or leaves |
cell.deploy.create |
A Cell is deployed for the first time |
cell.deploy.update |
An existing Cell is redeployed |
cell.delete |
A Cell is deleted |
vault.set |
A vault secret is set or replaced |
vault.delete |
A vault secret is deleted |
gate.link.created |
A gate capability link is minted |
gate.link.revoked |
A capability link is revoked |
gate.session.revoked |
A gate viewer session is revoked |
vesicle.capture.reveal |
A vesicle capture body is read in full |
billing.entitlements |
The account's entitlements change |
account.closed |
A closure is scheduled |
account.close_cancelled |
A scheduled closure is cancelled |
account.purged |
A closure completes and the account is destroyed |
Gate sign-ins are not in the feed: one row per visitor sign-in on a gated Cell would drown everything else. Per-request traffic is a different thing entirely and lives in analytics and the access log.
Retention
The feed holds 30 days. Records older than that are deleted by a background prune, from the feed and from the store behind it. There is no longer-lived copy to ask for, so export anything you need to keep — see exporting your data, whose events block carries up to 1000 rows from the same 30-day window.
Reading it over the API
curl -H "Authorization: Bearer $TISSUE_TOKEN" \
"https://api.tissue.systems/v1/account/events?limit=50"
{
"events": [
{
"action": "cell.deploy.update",
"actor_email": "ada@example.com",
"target": "my-api",
"detail": "{\"kind\":\"js\"}",
"created_at": 1754870400
}
],
"next_before": 1754870399
}
| Parameter | Meaning |
|---|---|
limit |
Rows per page, 1–500. Default 50 |
before |
Keyset cursor in unix seconds, exclusive. Pass the previous response's next_before |
action |
Exact action string from the table above |
Paging walks backwards in time: request a page, then pass its next_before as before for the next one. next_before is null when the window is exhausted. The cursor is a timestamp rather than a row id because row ids are platform-wide — an id cursor would tell one account how much every other account writes.
Five fields come back per row and no more: action, actor_email, target, detail, created_at. target is the name of the thing acted on, which for deploys, gate changes and vault changes is the Cell name and for member.* rows is the other person's email address; detail is a small JSON document carried as a string, or null. A member.removed row carries {"role":…,"self":…}, where self is true when someone left on their own rather than being removed by an administrator. A vault event names the Cell, never the key's value. Source IP, server, and internal row ids stay inside the platform. An action taken by the platform itself reports actor_email as system.
An action value that is not in the table returns an empty page, not an error. The list of visible actions is fixed, and answering differently for an unlisted one would make the endpoint a way to discover the operator-only actions that exist.
The endpoint needs the events:read scope. A session holds it at every role; an API token needs it granted explicitly.
See also
- Exporting your data: the same events inside a full account export
- Members and roles: who can read the feed
- Analytics & Access Log: per-request traffic data, which this feed is not