Skip to main content

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 activity stream is not an audit log

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
Path casing

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:

FormExampleNotes
An Oid tokenStory:1220The normal case. Resolved to the momentless token internally.
A workitem numberS-01047The user-visible number. Convenient, but costs an extra lookup.

If the value resolves to neither, the request returns 404 Not Found.

Number lookup is workitem-only

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​

ParameterTypeDefaultDescription
anchorDatedatetimenow (UTC)The point in time to read from.
directionenumBackBack for activity earlier than the anchor, Forward for later. Case-insensitive.
maxCountinteger25Number of activities to return.
verbsstringnone (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.

Request
curl "https://{host}/{instance}/api/ActivityStream/Story:1220/count" \
-H "Authorization: Bearer <access-token>"
200 OK
42
Undocumented in the original reference

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.

First page
curl "https://{host}/{instance}/api/ActivityStream/Story:1220?maxCount=25" \
-H "Authorization: Bearer <access-token>" \
-H "Accept: application/json"
Next page — anchored on the last entry's time
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:

VerbTypical meaning
AddedA value was added to a multi-value relation.
BlockedThe item was marked blocked.
DeletedThe asset was deleted (asset state 255).
DeprecatedThe asset was deprecated.
ClosedThe asset was closed or quick-closed.
CreatedThe asset was created.
MigratedThe asset was migrated.
MovedThe asset was moved — typically to a different project.
ReopenedA closed asset was reopened.
RemovedA value was removed from a multi-value relation.
UnBlockedA block was cleared. Note the internal capital B.
UpdatedOne or more attributes were set.
UndeletedA deleted asset was restored.
ActivatedThe asset was activated.
DeactivatedThe asset was deactivated.
TransformedThe asset was transformed into another type.
PinnedThe item was pinned.
UnpinnedThe item was unpinned.
Don't switch exhaustively on this list

Treat the table above as the current set, not a closed one, and handle any unrecognized verb gracefully rather than erroring on it.

Verb filtering is case-sensitive

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.