Agent Primer
This page briefs an AI agent on calling the Agility API. It is written for models, not people: dense, imperative, and exhaustive about failure modes. Every rule links the page that owns the full explanation — when this page and an owning page disagree, the owning page wins.
Choosing a Surface
| Task | Use |
|---|---|
| Read one asset, or write attributes | rest-1.v1/Data/<Type> — rest-1 |
| Read with shaped/nested JSON projections | query.v1 (read-only) — query.v1 |
| Create/update/execute in bulk, aliases | api/asset — Bulk API |
| Discover types, attributes, operations | meta.v1 (no auth) — meta.v1 |
| Resolve display names, localize tags | loc-2.v1 (no auth) — loc-2.v1 |
| Instance settings: attachment size limit, time zone, build version | config.v1 (no auth, XML only) — config.v1 |
| Read past values / change history | rest-1.v1/Hist/<Type> and asof — moments |
| Read member-scope role assignments | api/ProjectRoles — guide |
| Link a human to an asset | assetdetail.v1?oid=… or ?Number=… — permalinks; never emit these for programs |
Non-Negotiable Query Rules
- Every list query carries an explicit selection and page. Omitting
them returns every default attribute of every matching asset.
rest-1.v1:sel=Name,Number&page=50,0(positional, size first).query.v1:"select": [...]and"page": {"size": 50, "start": 0}(named, both keys required — omittingstartis a server error). Never port the positional form intoquery.v1or vice versa. Owner. - Do not alias.
"Name as Title"and"from": "Story as s"parse and are silently discarded — response keys are always the attribute tokens. Owner. - A paged response reports no total unless you ask:
rest-1.v1omits thetotalattribute,api/assetreportsnull; sendneedTotal=truewhen paging off the count, and treat its absence as "unknown", not zero.query.v1never returns a total at all. Owner. - Never invent attribute names. Fetch
meta.v1/<Type>and use the tokens it returns. Custom fields (Custom_*) vary per instance. Owner. - Resolve a UI word to a system name in this order: the
display-names table → its
informal-names and false-friends sections → assume an instance
terminology override and enumerate via
meta.v1+loc-2.v1(procedure). Beware: "Planning Level" usually meansScope, notPlanningLevel; "Message" is an inbox notification, not a comment. query.v1responses are double-wrapped — one array per query in the request document:[[...results...]]. Dotted select tokens come back as flattened keys ("Scope.Name"); bare relation selects return{"_oid": "..."}objects. Owner.- Fetch by OID with
"where": {"ID": "Story:1207"}(query.v1) or the URL path (rest-1). Match on OIDs, never on display names — display names are localized, instance-configurable, and not unique.
Non-Negotiable Write Rules
rest-1.v1JSON writes wrap every attribute:{"Attributes": {"Name": {"value": "...", "act": "set"}}}. Multi-value relations use"act": "add"/"remove". Owner.api/assetdocuments are named commands, one aliased command per array element:[{"@alias": {"AssetType": "Story", ...}}, {"@next": {"from": "@alias", "update": {...}}}]. Aliases resolve in order. Never put two@keys in one object: two siblings happen to work, three or more fail withInvalid key at node(s)and nothing is created. Owner.- Operations execute as
"execute": "Delete"(no arguments) or"execute": {"op": "AssignToScopeWithRole", "args": {...}}(parameterized). Awithblock does not pass operation arguments. Owner. - Never write a Rank attribute (
Order, AttributeTypeRank) with a numeric set — the server rejects it (Violation'NotSupported). Rank moves are relative, and rank changes leave no history. - Closed assets accept backfill only: writing an attribute that
already has a value fails with
Violation'ClosedAssetCannotEditExistingValues. Owner. Deleteis soft and recoverable (Undelete);Inactivatecloses (AssetState Closed). A closed asset cannot be deleted (Violation'AssetCannotDeleteClosed). Owner.- Status writes must be in the team's allowed set when the team
enforces a process (
Violation'PrimaryWorkitemCannotHaveInvalidStatus). Askapi/ValidValuesbefore writing, or inspectTeam.HasProcess/Team.SelectedValues. Owner. - A 200 from an operation means accepted, not transitioned. Some
redundant operations no-op with a new history moment (
Reactivateon an Active asset); others fail a rule. Read the asset's state back when the transition matters. Owner.
Error Handling
- Violations return structured tags (
Violation'...). The tags are localizable throughloc-2.v1; unresolved tags echo back unchanged, so blanket resolution is always safe. Owner. - An unparseable
api/assetdocument returns an opaque 500, not a 400 — do not retry unchanged; fix the document shape. - A 400
Wrong OID AssetTypemeans the relation's declared type rejects the target. Check the attribute'sRelatedAssettype inmeta.v1— and do not generalize between sibling types (Task.ParentandTest.Parentare typed differently). Owner.
Common Recipes
- Comment on a workitem (with a mention): create a
Conversation, anExpressionwithBelongsTo(or reply withInReplyTo), and anchor viaMentions. One-request payload: working with comments. - Scope-tree filtering:
Scope.ParentMeAndUp[Schedule=$S;ScopeLabels=$L]=$Scopewithwithvariables; arrays inwithare in-list matches. For large trees, precompute the scope set first. Owner. - Who did what, when:
Histqueries withHistory[...]projections;DoneDateis stamped when EffectiveAssetState reaches Closed. Not every attribute is tracked. Owner. - Grant access: default role via
Member.Scopesadd; a specific role via theAssignToScopeWithRole/AssignMemberWithRoleoperations; read back viaapi/ProjectRoles, never via asset queries. Owner.
Authentication
Access tokens never expire and carry the member's full rights — send
Authorization: Bearer <token>. Basic auth is a dev/demo configuration
only; production instances almost always use SSO. OAuth2 has never been
supported despite legacy naming. Owner.