Activity Stream (api/ActivityStream)
The activity stream is a read-only, human-oriented feed of what has happened to an asset: who did what, when, and what changed. It is the data behind the activity panel in the Agility UI, exposed directly.
When to Use It — and When Not To
The stream is not guaranteed to contain every change to an asset. It is a curated, presentation-oriented feed, and some changes are deliberately not surfaced in it.
For an authoritative accounting of changes, use asset history — the
Hist namespace on rest-1.v1, or an asof query on
query.v1. Know that history has limits of its own: a few
attributes are not tracked at all — rank order (Order) changes, for example, leave no
history — and neither surface offers a way to list which changes it records. Do not build
compliance, audit or reconciliation logic on the activity stream.
Use the activity stream when you want to render a "recent activity" feed with the same content and phrasing the product itself shows. Use asset history when you need completeness.
Endpoint
GET ~/api/ActivityStream/:streamName
The route is registered as api/ActivityStream — capital A, capital S
Some older navigation labels showed a lowercase
activityStream, which is why both spellings circulate.
ASP.NET routing is case-insensitive, so api/activitystream reaches the same handler in
practice. api/ActivityStream is the canonical form and is what this documentation uses. If
you are behind a proxy or gateway that normalizes or case-matches paths, use the canonical
casing.
The stream is identified by a stream name, which the server resolves in one of two ways:
| Form | Example | Notes |
|---|---|---|
| An Oid token | Story:1220 | The normal case. Resolved to the momentless token internally. |
| A workitem number | S-01047 | The user-visible number. Convenient, but costs an extra lookup. |
If the value resolves to neither, the request returns 404 Not Found.
The number form searches the Workitem asset type. It works for stories, defects, tasks and
tests, but not for assets outside that hierarchy. Prefer the Oid token — it is unambiguous and
avoids the search.
Deleted assets still have a resolvable stream: the lookup runs with ConsiderDeleted enabled,
so you can read the activity of something that has since been deleted.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
anchorDate | datetime | now (UTC) | The point in time to read from. |
direction | enum | Back | Back for activity earlier than the anchor, Forward for later. Case-insensitive. |
maxCount | integer | 25 | Number of activities to return. |
verbs | string | none (no filter) | Comma-separated list of verbs to filter on. Case-sensitive. |
Any parameter that fails to parse returns 400 Bad Request — the request is rejected rather
than silently falling back to the default.
Counting a Stream
GET ~/api/ActivityStream/:streamName/count
Returns the total number of activities in the stream as a bare integer — not JSON-wrapped,
and not affected by maxCount, verbs or the other query parameters.
curl "https://{host}/{instance}/api/ActivityStream/Story:1220/count" \
-H "Authorization: Bearer <access-token>"
42
The /count route was absent from the published reference material.
Paging Through a Stream
There is no page number. Paging is done by moving the anchor: read a page with
direction=Back, take the time of the last entry, and use it as the next request's
anchorDate.
curl "https://{host}/{instance}/api/ActivityStream/Story:1220?maxCount=25" \
-H "Authorization: Bearer <access-token>" \
-H "Accept: application/json"
curl "https://{host}/{instance}/api/ActivityStream/Story:1220?maxCount=25&anchorDate=2014-04-22T14:11:01.1175003Z&direction=Back" \
-H "Authorization: Bearer <access-token>" \
-H "Accept: application/json"
Two activities can share a timestamp, so a naive anchor-on-last-time loop can repeat or skip an entry at a page boundary. De-duplicate on the activity's identity when stitching pages together.
Verbs
verb describes what the actor did. Filter the feed by passing a comma-separated list:
GET ~/api/ActivityStream/Story:1220?verbs=Created,Updated,Closed
The complete set defined by the server is:
| Verb | Typical meaning |
|---|---|
Added | A value was added to a multi-value relation. |
Blocked | The item was marked blocked. |
Deleted | The asset was deleted (asset state 255). |
Deprecated | The asset was deprecated. |
Closed | The asset was closed or quick-closed. |
Created | The asset was created. |
Migrated | The asset was migrated. |
Moved | The asset was moved — typically to a different project. |
Reopened | A closed asset was reopened. |
Removed | A value was removed from a multi-value relation. |
UnBlocked | A block was cleared. Note the internal capital B. |
Updated | One or more attributes were set. |
Undeleted | A deleted asset was restored. |
Activated | The asset was activated. |
Deactivated | The asset was deactivated. |
Transformed | The asset was transformed into another type. |
Pinned | The item was pinned. |
Unpinned | The item was unpinned. |
Treat the table above as the current set, not a closed one, and handle any unrecognized verb gracefully rather than erroring on it.
verbs values are parsed with an exact, case-sensitive enum match. verbs=updated does not
mean Updated — it returns 400 Bad Request, as does any unrecognized name. One bad entry
rejects the whole request; there is no partial filtering.
Note the irregular casing this makes significant: UnBlocked has an internal capital B, while
Undeleted and Unpinned do not.
This is inconsistent with direction, which is parsed case-insensitively.
Related Topics
- Query activity — full request and response walkthrough- rest-1.v1 — asset history, for a complete change record
- Webhooks — push notification instead of polling this feed
- Terminology — Oid tokens