Members, Roles, and Scopes
Access in Agility is a triangle: a Member (who) holds a Role (what
they may do) on a Scope (where). A role assigned on a scope applies to
that scope's whole subtree; the effective role at any scope is the nearest
assignment at or above it. Each member also carries a DefaultRole —
the role used when membership is granted without naming one.
The asset model tells only part of this story. Member.Scopes (and its
reverse, Scope.Members) records membership, and Member.DefaultRole
the default — but the member-scope-role assignment itself is not an
asset. No asset type carries it, so no rest-1.v1 or query.v1 query
can return "what role does this member hold on this scope." Writing and
reading assignments each have their own path.
Granting Membership at the Default Role
Adding a scope to Member.Scopes grants that member their default role on
the scope (and, by inheritance, its subtree):
{
"from": "Member:3907",
"update": { "Scopes": { "add": ["Scope:1071"] } }
}
Updating from the other side — Scope.Members — is equivalent.
Granting a Specific Role
Naming the role takes one of two parameterized operations — the same assignment reached from either corner of the triangle:
Member.AssignToScopeWithRolewith{ Scope, Role, IsOwner }Scope.AssignMemberWithRolewith{ Member, Role, IsOwner }
{
"from": "Member:1040",
"execute": {
"op": "AssignToScopeWithRole",
"args": { "Scope": "Scope:1503", "Role": "Role:3", "IsOwner": true }
}
}
The Bulk API's operations page covers
parameterized execution in detail, including running the assignment
against many members or scopes at once. Repeating the operation with a
different role replaces the assignment; IsOwner additionally marks the
member as an owner of the project.
Roles themselves are queryable assets (/rest-1.v1/Data/Role) — note
their Name values return as localization tags (Role.Name'Project Lead), which resolve through the
localization API like any
display name.
Reading Assignments: the Project Roles API
Because assignments aren't assets, reading them has a
dedicated endpoint: api/ProjectRoles, grouped
from either direction:
GET ~/api/ProjectRoles/ByMember?where=ID='Member:20'
GET ~/api/ProjectRoles/ByProject?where=ID='Scope:0'
Each row reports the effective role — inherited assignments included —
plus isOwner and the member's defaultRole:
{
"member": { "oidToken": "Member:20", "name": "Administrator", "defaultRole": { "oidToken": "Role:1", "name": "System Admin" } },
"projectRoles": [
{ "isOwner": true, "project": { "oidToken": "Scope:0", "name": "System (All Projects)" }, "role": { "oidToken": "Role:1", "name": "System Admin" } }
]
}
Details worth knowing:
- Filter tokens are relative to the grouping asset:
where=ID='Member:20', notwhere=Member.ID='Member:20'. Each direction takes a second filter for the other side —projectswhereonByMember,memberswhereonByProject— pluspageandsort. - A bare
GET ~/api/ProjectRoles/ByMember(no parameters) returns the endpoint's own usage documentation as a RAML document.
Provision a Member
Finding, creating and deactivating members is a common administrative automation, separate from the role and scope questions above.
Find an existing member — Username is unique, so a lookup
returns at most one member:
{
"from": "Member",
"where": { "Username": "andre.agile" },
"select": ["Name", "Username", "Email"]
}
Email is not unique, so a where match on it can return more than one
Member — bound the result with page if you use it as the lookup key
instead.
Create a member, providing the required fields plus the fields most useful for administration:
{
"AssetType": "Member",
"Name": "Andre Agile",
"Username": "andre.agile",
"Nickname": "Andre",
"Password": "<initial-password>",
"Email": "andre.agile@example.com",
"IsCollaborator": false,
"DefaultRole": "Role:4"
}
See Creating assets for the full
create-command shape, including resolving DefaultRole by name instead of
OID token.
Update a member the same way as any other asset:
{
"from": "Member:30633",
"update": { "Phone": "555-555-1212" }
}
Deactivate a member with the Inactivate operation. The member loses
system access (a sign-in that worked returns 401 afterwards) but stays
queryable with AssetState Closed:
{ "from": "Member:30633", "execute": "Inactivate" }
See Invoking operations for the operation syntax in full.
Prefer Inactivate when someone leaves: the member keeps its place in
history, so ownership and time-by-person reports stay accurate. Delete
removes the member from every query that doesn't request deleted assets,
historical ones included, and from Agility's by-member reports, so their
past ownership and logged time stop being attributed to them. Delete only a
member created by mistake, or one whose username you need to reuse. An
inactive member can't be deleted; reactivate it first.
Related Topics
-
Product feature: Assigning a project role and Which project role should I choose? — the UI and semantics behind the assignments this guide automates.
-
Project Roles API — the endpoint in full, including its self-published RAML specification
-
Bulk API operations — parameterized execution
-
System names and display names — resolving role-name tags