Watch (api/watch)
Manages the calling member's asset subscriptions — "watching" an asset so they are notified about it.
Everything here is scoped to the authenticated member. There is no parameter for acting on another member's watches, and the list endpoint returns only your own.
api/watch is per-member notification within Agility. Webhooks are
instance-level HTTP callbacks to an external system. They share the word "subscription" and
nothing else.
All routes require authentication.
Subscribe or Unsubscribe
POST ~/api/watch
Content-Type: application/json
{ "oid": "Story:1234", "action": "Subscribe" }
| Field | Required | Description |
|---|---|---|
oid | yes | OID token of the asset to watch or unwatch |
action | yes | Subscribe or Unsubscribe |
action is matched case-insensitively, so subscribe, Subscribe and SUBSCRIBE all
work.
Response
{ "oid": "Story:1234", "isWatching": true, "action": "subscribe" }
Note the echoed action comes back lower-case regardless of how you sent it. Do not
round-trip it into a case-sensitive comparison.
isWatching is true after a subscribe and false after an unsubscribe.
Errors
All are 400. The validation wording varies between versions — key on the
status code and the missing field, not on the message text:
| Body | Cause |
|---|---|
"Missing request body" | No body sent |
| A ModelState object | oid or action missing — both are [Required] |
"Invalid action" | action is null, or is neither Subscribe nor Unsubscribe |
Check One Asset
GET ~/api/watch?oid=Story:1234
{ "oid": "Story:1234", "isWatching": false }
Returns 400 with "Missing oid" when the parameter is present but blank
(?oid=). Omitting the parameter entirely returns 405 instead — a GET with
no query routes against the POST-only subscribe endpoint.
List Everything Watched
GET ~/api/watch/list
{ "watchedOids": ["Story:1234", "Defect:5678"] }
The watched OIDs for the calling member. Note the array is wrapped in an object rather than returned bare.
What a Subscribe Actually Creates
A watch is not hidden state — it is ordinary assets, and api/watch is a
convenience that assembles them so you don't have to know the machinery. A
subscribe creates:
- a
Subscription—Nameis a generated title ("Watching Logon (S-01001)"),EventDefinitionis the watched type's changed event (Story.Changed),Subscriberis the calling member; - a
SubscriptionTermin itsFilterTerms—AttributeToken: "ID",Valuethe watched OID — created in the subscription's context so its required pieces default correctly.
Both are queryable:
{
"from": "Subscription",
"select": ["Name", "EventDefinition", "FilterTerms.AttributeToken", "FilterTerms.Value"],
"where": { "Subscriber": "Member:20" },
"page": { "size": 50, "start": 0 }
}
Unsubscribing removes them again.
Two consequences worth knowing:
- Watches are the narrow case of a wider model: the application's
subscription editor composes
SubscriptionTerms over attributes such asScope.ParentMeAndUp,Owners,StatusandTeamagainst any event definition — richer subscriptions than a single-asset watch. - Building the same assets by hand through the Bulk API needs the term
created in its subscription's context — the
#ContextOidinitialization — which is exactly the machineryapi/watchexists to spare you.
Related
- Webhooks — external HTTP callbacks, a different mechanism
- Activity stream — what changed on an asset