Skip to content

.NET SDK β€” Client Reference: GroupClientΒΆ

Overview

Use Context.GroupClient to manage Organisations, Tenants, Groups, Roles, and Members in AIForged. This reference covers reading groups, creating/updating/deleting groups, and managing roles and role members.

  • Get groups by ID, user, tenant, or tenant user.
  • Create, update, and delete groups.
  • Manage roles (create, copy, consolidate, update, delete) and list users assigned to roles.

Authentication and endpoint

  • Base URL: https://portal.aiforged.com
  • Authentication: include the HTTP header X-Api-Key with your API key on all requests.

PrerequisitesΒΆ

  1. Install the SDK.

    dotnet add package AIForged.SDK
    
  2. Initialize the context with API key authentication.

    using AIForged.API;
    
    var baseUrl = Environment.GetEnvironmentVariable("AIFORGED_BASE_URL") ?? "https://portal.aiforged.com";
    var apiKey  = Environment.GetEnvironmentVariable("AIFORGED_API_KEY")  ?? throw new Exception("AIFORGED_API_KEY not set.");
    
    var cfg = new Config { BaseUrl = baseUrl, Timeout = TimeSpan.FromMinutes(5) };
    await cfg.Init();
    cfg.HttpClient.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
    
    var ctx = new Context(cfg);
    
    // Access the client
    var groups = ctx.GroupClient;
    

Connection check

After initialization, call a lightweight endpoint such as:

await ctx.GetCurrentUserAsync();

to verify connectivity and credentials.

MethodsΒΆ

Get group by IDΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> GetAsync(int? id, bool? includeUsers);
System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> GetAsync(int? id, bool? includeUsers, System.Threading.CancellationToken cancellationToken);
  • Parameters:
    • id: Group identifier.
    • includeUsers: When true, role membership collections are populated (see note below).
var resp = await ctx.GroupClient.GetAsync(id: 101, includeUsers: true);
var group = resp.Result;

includeUsers behavior

When includeUsers is true, the Users property on GroupRoleViewModel instances in the returned object graph is populated.

Get groups by userΒΆ

System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupViewModel>>> GetByUserAsync(string userId, bool? includeUsers);
System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupViewModel>>> GetByUserAsync(string userId, bool? includeUsers, System.Threading.CancellationToken cancellationToken);
var resp = await ctx.GroupClient.GetByUserAsync(userId: "user-123", includeUsers: false);
var userGroups = resp.Result;

Get groups by tenantΒΆ

System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupViewModel>>> GetByTenantAsync(int? tenantId);
System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupViewModel>>> GetByTenantAsync(int? tenantId, System.Threading.CancellationToken cancellationToken);
var resp = await ctx.GroupClient.GetByTenantAsync(tenantId: 42);
var tenantGroups = resp.Result;

Get groups by tenant userΒΆ

System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupViewModel>>> GetByTenantUserAsync(string userId);
System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupViewModel>>> GetByTenantUserAsync(string userId, System.Threading.CancellationToken cancellationToken);
var resp = await ctx.GroupClient.GetByTenantUserAsync(userId: "user-123");
var tenantUserGroups = resp.Result;

Create a groupΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> CreateAsync(GroupViewModel group);
System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> CreateAsync(GroupViewModel group, System.Threading.CancellationToken cancellationToken);
var newGroup = new GroupViewModel
{
    UserId = "owner-user-id",
    Name = "Finance",
    Type = GroupType.Tenant,
    Status = GroupStatus.Active
};

var created = await ctx.GroupClient.CreateAsync(newGroup);
var group = created.Result;

Update a groupΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> UpdateAsync(GroupViewModel group);
System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> UpdateAsync(GroupViewModel group, System.Threading.CancellationToken cancellationToken);
var g = (await ctx.GroupClient.GetAsync(101, includeUsers: false)).Result;
g.Name = "Finance & Operations";
var updated = await ctx.GroupClient.UpdateAsync(g);

Delete a groupΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> DeleteAsync(int? id);
System.Threading.Tasks.Task<PortalResponse<GroupViewModel>> DeleteAsync(int? id, System.Threading.CancellationToken cancellationToken);
var deleted = await ctx.GroupClient.DeleteAsync(101);

404 handling

If a resource is not found, the server returns HTTP 404 via SwaggerException. Always use try/catch and inspect ex.StatusCode when deleting or reading by ID.

Get roles in a groupΒΆ

System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupRoleViewModel>>> GetRolesAsync(int? groupId, GroupRoleType? type, bool? includeUsers);
System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupRoleViewModel>>> GetRolesAsync(int? groupId, GroupRoleType? type, bool? includeUsers, System.Threading.CancellationToken cancellationToken);
var roles = (await ctx.GroupClient.GetRolesAsync(groupId: group.Id, type: null, includeUsers: true)).Result;

includeUsers behavior

For GetRolesAsync, includeUsers=true ensures the Users property on each returned GroupRoleViewModel is populated.

Get users for a roleΒΆ

System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupRoleUserViewModel>>> GetUsersByRoleAsync(int? roleId);
System.Threading.Tasks.Task<PortalResponse<System.Collections.ObjectModel.ObservableCollection<GroupRoleUserViewModel>>> GetUsersByRoleAsync(int? roleId, System.Threading.CancellationToken cancellationToken);
var roleUsers = (await ctx.GroupClient.GetUsersByRoleAsync(roleId: 555)).Result;

Create a roleΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> CreateRoleAsync(GroupRoleViewModel grouprole);
System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> CreateRoleAsync(GroupRoleViewModel grouprole, System.Threading.CancellationToken cancellationToken);
var role = new GroupRoleViewModel
{
    GroupId = group.Id,
    Name = "Project Administrators",
    Type = GroupRoleType.Administrator | GroupRoleType.Projects,
    Status = GroupRoleStatus.Active
};

var createdRole = await ctx.GroupClient.CreateRoleAsync(role);

Compose permissions

GroupRoleType is a flags enum. Combine permissions with bitwise OR:

var flags = GroupRoleType.Administrator | GroupRoleType.Projects | GroupRoleType.Download;

Copy a role (with users) to another groupΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> CopyRoleAsync(int? groupRoleId, int? toGroupId);
System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> CopyRoleAsync(int? groupRoleId, int? toGroupId, System.Threading.CancellationToken cancellationToken);
var copied = await ctx.GroupClient.CopyRoleAsync(groupRoleId: 777, toGroupId: 202);

Consolidate rolesΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> ConsolidateRolesAsync(int? groupId, int? projectId, System.Collections.Generic.List<int> groupRoleIds);
System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> ConsolidateRolesAsync(int? groupId, int? projectId, System.Collections.Generic.List<int> groupRoleIds, System.Threading.CancellationToken cancellationToken);
var consolidated = await ctx.GroupClient.ConsolidateRolesAsync(
    groupId: group.Id,
    projectId: null,
    groupRoleIds: new List<int> { 101, 102, 103 }
);

Update a roleΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> UpdateRoleAsync(GroupRoleViewModel grouprole);
System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> UpdateRoleAsync(GroupRoleViewModel grouprole, System.Threading.CancellationToken cancellationToken);
var r = createdRole.Result;
r.Name = "Project Admins";
var updatedRole = await ctx.GroupClient.UpdateRoleAsync(r);

Delete a roleΒΆ

System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> DeleteRoleAsync(int id);
System.Threading.Tasks.Task<PortalResponse<GroupRoleViewModel>> DeleteRoleAsync(int id, System.Threading.CancellationToken cancellationToken);
var deletedRole = await ctx.GroupClient.DeleteRoleAsync(id: 555);

ModelsΒΆ

GroupViewModelΒΆ

Represents a Group (Organisation, Tenant, Users, Billing, Partner).

Property Type Notes
Id int
Type GroupType
Status GroupStatus
UserId string Required; [StringLength(450, MinimumLength = 1)]
Name string [StringLength(256)]
DTC DateTime UTC
DTM DateTime UTC
Domain string [StringLength(1024)]
TenantId int?
Info string
Address string
VATNo string
TenantName string
UserName string
UserFullName string
UserDisplayName string
IsOwner bool
IsAdmin bool
IsPartner bool
Rights string
RoleCount int
UserCount int
ProjectCount int
GroupCount int
ConsolidateCount int
Children ObservableCollection
Projects ObservableCollection
Roles ObservableCollection

Timestamp convention

In AIForged, all timestamps are UTC. This applies to DTC and DTM across Group and GroupRole models.

GroupRoleViewModelΒΆ

Represents a role within a group, optionally scoped to a project.

Property Type Notes
Id int
GroupId int
ProjectId int?
Type GroupRoleType Flags enum
Status GroupRoleStatus
Name string [StringLength(256)]
DTC DateTime UTC
DTM DateTime UTC
Start DateTime?
End DateTime?
Group GroupViewModel
Project ProjectViewModel
Users ObservableCollection Populated when includeUsers=true
Related ObservableCollection
DisplayName string

EnumsΒΆ

GroupTypeΒΆ

public enum GroupType
{
    Default = 0,
    Partner = 1,
    Tenant = 10,
    Billing = 11,
    Users = 12
}

GroupStatusΒΆ

public enum GroupStatus
{
    Active = 0,
    Deleted = 99
}

GroupRoleTypeΒΆ

[System.Flags]
public enum GroupRoleType
{
    Owner = 1,
    Administrator = 2,
    Partner = 4,
    User = 8,
    Projects = 32,
    Train = 256,
    Verify = 512,
    Manage = 1024,
    VerifyAdmin = 1536,
    Download = 2048,
    Delete = 4096,
    PromptDesign = 8192,
    ViewOnly = 32768,
    Document = 65536,
    VerifyDoc = 66048,
    DocDownload = 67584,
    Layout = 131072,
    DocLayout = 196608,
    DocLayoutTrain = 196864,
    Shred = 262144,
    VerifyShred = 262656,
    ViewShred = 294912,
    Billing = 524288,
    BillingAdmin = 525312,
    BillingView = 557056,
    Workflow = 1048576,
    WorkManage = 1049600,
    WorkView = 1081344,
    Rule = 2097152,
    RuleManage = 2098176,
    RuleView = 2129920,
    DataSet = 4194304,
    DataSetAdmin = 4195328,
    DataSetView = 4227072,
    Developer = 8326944
}

GroupRoleStatusΒΆ

public enum GroupRoleStatus
{
    Active = 0,
    Deleted = 99
}

ExamplesΒΆ

Create a tenant group and admin roleΒΆ

  1. Create the group.

    var tenant = (await ctx.GroupClient.CreateAsync(new GroupViewModel
    {
        UserId = "owner-user-id",
        Name = "Acme Tenant",
        Type = GroupType.Tenant,
        Status = GroupStatus.Active
    })).Result;
    
  2. Create a role with combined permissions.

    var adminRole = (await ctx.GroupClient.CreateRoleAsync(new GroupRoleViewModel
    {
        GroupId = tenant.Id,
        Name = "Tenant Admins",
        Type = GroupRoleType.Owner | GroupRoleType.Administrator | GroupRoleType.Projects,
        Status = GroupRoleStatus.Active
    })).Result;
    

Project scoping

To scope a role to a specific project, set GroupRoleViewModel.ProjectId before creating the role.

List groups for a user and include role membersΒΆ

var groupsForUser = (await ctx.GroupClient.GetByUserAsync("user-123", includeUsers: true)).Result;
foreach (var g in groupsForUser ?? new System.Collections.ObjectModel.ObservableCollection<GroupViewModel>())
{
    var roles = g.Roles ?? new System.Collections.ObjectModel.ObservableCollection<GroupRoleViewModel>();
    foreach (var role in roles)
    {
        var users = role.Users;
        // users is populated when includeUsers=true
    }
}

Copy a role (with users) to another groupΒΆ

var copiedRole = (await ctx.GroupClient.CopyRoleAsync(groupRoleId: 1234, toGroupId: 5678)).Result;

Consolidate multiple rolesΒΆ

var result = (await ctx.GroupClient.ConsolidateRolesAsync(
    groupId: 999,
    projectId: null,
    groupRoleIds: new System.Collections.Generic.List<int> { 200, 201, 202 }
)).Result;

ReferenceΒΆ

flowchart TD
    A["Group"] --> B["Roles"]
    B["Roles"] --> C["Role Users"]
    A["Group"] --> D["Projects"]
    A["Group"] --> E["Child Groups"]

TroubleshootingΒΆ

  • Retrieve/update/delete failures
    • Wrap calls in try/catch for SwaggerException and inspect ex.StatusCode and ex.Response.
  • No users returned for roles
    • Ensure includeUsers=true on GetAsync or GetRolesAsync; otherwise, role Users collections are not populated.
  • Timestamps handling
    • DTC and DTM are UTC. Convert to local time for display when needed.