Skip to main content

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:

FieldTells you
TokenThe full name (AssetType.Attribute) — unambiguous in any context
AttributeTypeThe data type — see attribute types
IsMultivalueWhether values are collections
IsRequiredMust be supplied when creating the asset
IsReadOnlyMaintained by the system; writes are rejected or ignored
IsCustomDefined by an administrator rather than shipped with the product
BaseThe ancestor type that actually declares the attribute
RelatedAssetFor relations: the asset type on the other end
ReciprocalRelationFor 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:

TypeExample on StoryNotes
TextName, NumberSingle-line strings
LongTextDescriptionRich/long content
NumericEstimateInteger or decimal
DateCreateDateUTC, ChangeDateUTCPrefer the …UTC twins for filtering — no timezone/DST surprises
BooleanIsDeleted, IsClosedTrue/false
StateAssetStateSystem lifecycle; read-only — change it with operations
RankOrderAn opaque ordering token — sort by it, never read or compare it
RelationScope, Owners, StatusSingle- or multi-value links to other assets

Two type-specific traps worth knowing early:

  • Rank values are not numbers you can reason about. Sort by Order to 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:

  1. Discover them from meta.v1 rather than hard-coding names
  2. Use the exact token, including the Custom_ prefix
  3. Check AttributeType and IsRequired before writing
  4. Ask for them explicitly. Custom fields are never part of the default selection, so a query that omits sel — or one that filters with where but does not name them in sel — returns none of them. List each Custom_… token you want (sel=Name,Custom_Region).

Best Practices​

  1. Select only what you need — every attribute costs something and every relation costs a join; see query size and performance.
  2. Read the definition before you write the value — IsReadOnly, IsRequired and AttributeType answer most "why did my update fail?" questions before they happen.
  3. Use Token names in logs and errors (Story.Name, not Name) — the same attribute name means different things on different types.
  4. Prefer UTC date attributes in filters and projections.