Attributes in Agility
Attributes are the named properties that hold an asset's data — names, estimates, dates, statuses, and relations to other assets. Everything you select, filter, or update in the API is an attribute.
The Attribute Definition
Every attribute is described by an attribute definition in the
Meta API. This is what GET /meta.v1/Story returns for
Story.Owners:
{
"_type": "AttributeDefinition",
"Name": "Owners",
"Token": "Story.Owners",
"AttributeType": "Relation",
"IsReadOnly": false,
"IsRequired": false,
"IsMultivalue": true,
"IsCanned": true,
"IsCustom": false,
"Base": { "tokenref": "Workitem.Owners" },
"RelatedAsset": { "nameref": "Member" },
"ReciprocalRelation": { "tokenref": "Member.OwnedWorkitems" }
}
The fields that drive integration decisions:
| Field | Tells you |
|---|---|
Token | The full name (AssetType.Attribute) — unambiguous in any context |
AttributeType | The data type — see attribute types |
IsMultivalue | Whether values are collections |
IsRequired | Must be supplied when creating the asset |
IsReadOnly | Maintained by the system; writes are rejected or ignored |
IsCustom | Defined by an administrator rather than shipped with the product |
Base | The ancestor type that actually declares the attribute |
RelatedAsset | For relations: the asset type on the other end |
ReciprocalRelation | For relations: the same link seen from the other side |
Attribute Types, Briefly
The attribute-types reference is the complete list; the ones you will meet constantly:
| Type | Example on Story | Notes |
|---|---|---|
Text | Name, Number | Single-line strings |
LongText | Description | Rich/long content |
Numeric | Estimate | Integer or decimal |
Date | CreateDateUTC, ChangeDateUTC | Prefer the …UTC twins for filtering — no timezone/DST surprises |
Boolean | IsDeleted, IsClosed | True/false |
State | AssetState | System lifecycle; read-only — change it with operations |
Rank | Order | An opaque ordering token — sort by it, never read or compare it |
Relation | Scope, Owners, Status | Single- or multi-value links to other assets |
Two type-specific traps worth knowing early:
Rankvalues are not numbers you can reason about. Sort byOrderto reproduce the UI's ordering; do not store, compare or do arithmetic on the values.- Date attributes come in local and UTC pairs (
ChangeDate/ChangeDateUTC). Filter and project the UTC ones in integrations.
Selecting Attributes
Name attributes directly, traverse relations with dots, and project multiple attributes of related assets with a nested subquery. Multi-value paths come back as arrays. This request and its real response:
{
"from": "Story",
"where": { "ID": "Story:1207" },
"select": [
"Name",
"Scope.Name",
"Owners.Name",
{ "from": "Children:Task", "select": ["Name", "ToDo"] }
]
}
[
[
{
"_oid": "Story:1207",
"Name": "Logon",
"Scope.Name": "Release 1.0",
"Owners.Name": ["Alfred Smith"],
"Children:Task": [
{ "_oid": "Task:1469", "Name": "Design Login Page", "ToDo": "0" },
{ "_oid": "Task:1470", "Name": "Code Login", "ToDo": "0" }
]
}
]
]
Note the response keys: a dotted selection arrives flattened under its
path string ("Scope.Name"), and a nested subquery arrives as an array of
objects under its from expression ("Children:Task" — the :Task is a
downcast selecting only the Task
children).
Filtering by Attributes
where matches exact values; filter takes the
full comparison grammar, with
values quoted:
{
"from": "Story",
"where": { "Scope": "Scope:0" },
"filter": ["Estimate>'2'", "ChangeDateUTC>='2026-01-01'"],
"select": ["Number", "Name", "Estimate"],
"page": { "size": 50, "start": 0 }
}
Filter on OIDs rather than names where you can — names are editable and localized; OIDs are stable.
Setting Attribute Values
Writes happen on two surfaces, each with its own shape — don't mix them:
rest-1.v1 takes XML, marking each attribute with an action:
<Asset>
<Attribute name="Name" act="set">Updated story name</Attribute>
<Relation name="Status" act="set">
<Asset idref="StoryStatus:134" />
</Relation>
</Asset>
See update examples for scalars, single relations, and multi-relation add/remove.
api/asset takes JSON or YAML update commands:
{
"from": "Story:1207",
"update": {
"Name": "Updated story name",
"Owners": { "add": ["Member:20"] }
}
}
See updating assets for the full command
shape, including multi-relation add/remove semantics.
Required and Read-Only Attributes
Read IsRequired and IsReadOnly from the Meta API rather than memorizing
lists. Verified examples from Story:
Name—IsRequired: true;Scope—IsRequired: true. A Story create without both fails.Number,CreateDateUTC,ChangeDateUTC—IsReadOnly: true, generated and maintained by the system.AssetState— read-only and only changeable through operations (Inactivate,Reactivate, …), never by direct update.
One timing subtlety: requiredness is enforced when values are written,
not retroactively — changing an attribute definition to required does not
fill it in on existing assets of that type. Those assets are not locked by
the missing value: updates to their other attributes succeed, and
Inactivate closes them with the required attribute still empty.
Custom Attributes
Administrators can add attributes to most types. They appear in the Meta API
like any other definition, flagged IsCustom: true; admin-created fields
have tokens beginning Custom_. Because they differ per instance:
- Discover them from
meta.v1rather than hard-coding names - Use the exact token, including the
Custom_prefix - Check
AttributeTypeandIsRequiredbefore writing - Ask for them explicitly. Custom fields are never part of the default
selection, so a query that omits
sel— or one that filters withwherebut does not name them insel— returns none of them. List eachCustom_…token you want (sel=Name,Custom_Region).
Best Practices
- Select only what you need — every attribute costs something and every relation costs a join; see query size and performance.
- Read the definition before you write the value —
IsReadOnly,IsRequiredandAttributeTypeanswer most "why did my update fail?" questions before they happen. - Use
Tokennames in logs and errors (Story.Name, notName) — the same attribute name means different things on different types. - Prefer UTC date attributes in filters and projections.
Related Topics
- Attribute types — the complete type list
- Attribute paths — dots, downcasts and path filters
- Meta API — discovering definitions
- Relations — the relation side of the model in depth