---
id: activity-stream
slug: /apis/activity-stream
title: 'Activity Stream (api/ActivityStream)'
description: 'Read-only feed of what happened to an asset — who did what, when — with verb filtering and date-anchored paging.'
sidebar_label: 'Overview'
sidebar_position: 1
tags: ['api', 'activity-stream', 'history', 'audit']

draft: false
---

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

:::warning 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`](/apis/rest-1), or an `asof` query on
[`query.v1`](/apis/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

```text
GET ~/api/ActivityStream/:streamName
```

:::note 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:

| Form                    | Example      | Notes                                                                 |
| ----------------------- | ------------ | --------------------------------------------------------------------- |
| An [Oid token](/apis/conventions/terminology#oid) | `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`**.

:::note 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

| 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

```text
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.

```bash title="Request"
curl "https://{host}/{instance}/api/ActivityStream/Story:1220/count" \
  -H "Authorization: Bearer <access-token>"
```

```text title="200 OK"
42
```

:::note 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`.

```bash title="First page"
curl "https://{host}/{instance}/api/ActivityStream/Story:1220?maxCount=25" \
  -H "Authorization: Bearer <access-token>" \
  -H "Accept: application/json"
```

```bash title="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:

```text
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.                                           |

:::note 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.
:::

:::danger 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.
:::

## Related Topics

- [Query activity](/apis/activity-stream/query) — full request and response walkthrough- [rest-1.v1](/apis/rest-1) — asset history, for a complete change record
- [Webhooks](/apis/webhooks) — push notification instead of polling this feed
- [Terminology](/apis/conventions/terminology) — Oid tokens
