Event Types
The eventTypes array on a subscription is where you say what you actually want to hear about.
Each entry is an independent rule; a subscription fires if any of its event types matches.
The Two Event Types
Agility records every asset creation and every asset change. Each event type entry declares which of the two it is watching:
type | Fires when |
|---|---|
AssetCreated | An asset of from is created. |
AssetChanged | An asset of from is modified. |
These are the only two accepted values. Anything else is rejected at subscription-create time with a message naming both.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
type | string | yes | AssetCreated or AssetChanged. |
from | string | yes | The asset type to watch, e.g. Story. Use the system name — see terminology. |
attributes | string[] | no | Restrict to changes touching these attributes. Omit to fire on any change. |
filter | string[] | no | Filter expressions the asset must satisfy. The full filter language — operators, value lists, unary existence and grouping all work here. |
with | object | no | Filter context — variable bindings substituted into filter. |
userContext | string | no | Oid token of a member whose visibility the event is evaluated under. |
select | array | no | Attribute paths to project into the delivered payload's snapshot. |
Building up an Event Type
Every Change to a Story
{
"type": "AssetChanged",
"from": "Story"
}
Only When Status Changes
attributes narrows the rule to changes that touch the listed attributes. Without it you are
notified of any change to the asset, which on a busy instance is a lot of traffic.
{
"type": "AssetChanged",
"from": "Story",
"attributes": ["Status"]
}
Only Stories in One Project
filter takes the same filter expressions as a query, and with binds the variables they
reference. Keeping the value in with rather than inlining it makes the subscription easy to
retarget later.
{
"type": "AssetChanged",
"from": "Story",
"attributes": ["Status"],
"filter": ["Scope=$Scope"],
"with": {
"$Scope": "Scope:0"
}
}
See the query grammar reference for the full filter syntax.
Only What a Particular Member Can See
Most assets in Agility are secured by their relationship to a Scope (project). Without
userContext, an event type sees everything — assets in every project, regardless of who
can normally view them.
userContext runs the evaluation as a specific member, so only changes visible to that member
produce events:
{
"type": "AssetChanged",
"from": "Story",
"attributes": ["Status"],
"userContext": "Member:1002"
}
userContext is a security control, not a convenienceAn event type without userContext will happily deliver data from projects the subscription's
creator could not otherwise read, to whatever URL you named. If the receiving system is not
trusted with instance-wide data, set userContext to a member with appropriately limited
visibility.
Note also that the original reference material contained the literal value "Memeber:1002" in
two of its examples — a misspelling of Member. An unresolvable Oid token here does not fail
open in a useful way; use the correct spelling.
Include Asset Details in the Delivery
By default the delivered payload identifies the asset by Oid and lists what changed, but tells
you nothing else about it. select projects additional attributes into the payload's
snapshot, using the same projection syntax as a query — including dot traversal across
relations:
{
"type": "AssetChanged",
"from": "Story",
"attributes": ["Status"],
"filter": ["Scope=$Scope"],
"with": {
"$Scope": "Scope:0"
},
"select": ["Name", "Owners.Name"]
}
The snapshot in the delivered payload then carries Name and each owner's Name, in the same
shape a query.v1 result would have. This is what lets a handler act on an
event without calling back into the API for context — worth doing, because it removes a
round-trip and avoids a race where the asset changes again before you read it.
attributes, pluralA common mistake is sending attribute (singular). Because api/webhook rejects unknown
keys instead of ignoring them, that produces a 400 rather than a silent misconfiguration.
See unknown keys are rejected on the create page for the mechanism.
A Complete eventTypes Array
Event types compose. This subscription fires on new Defects anywhere, and on Story status changes in one project:
{
"eventTypes": [
{
"type": "AssetCreated",
"from": "Defect",
"select": ["Name", "Number", "Priority"]
},
{
"type": "AssetChanged",
"from": "Story",
"attributes": ["Status"],
"filter": ["Scope=$Scope"],
"with": { "$Scope": "Scope:0" },
"select": ["Name", "Status.Name", "Owners.Name"]
}
]
}
Each delivered event names the eventType that produced it, so a handler can dispatch on it.
Related Topics
- Create a subscription
- Webhook payload — what
selectproduces - Query grammar reference — filter and projection syntax
- Attribute definition syntax