What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
SDKs
Manage an instance's users and roles, look up the signed-in user, manage Personal Access Tokens and get Fetch API keys with the Agility CMS .NET Management SDK 2.0.
This page has moved — the Management SDK is now documented elsewhere. The JavaScript and .NET guides have been merged into a single set with per-language code tabs. Read the current guide.
client.InstanceUsers manages who can use an instance and which roles they have. This article also covers the signed-in user (client.ServerUsers), Personal Access Tokens (client.PersonalAccessTokens) and an instance's Fetch API keys (client.OAuth).
Note: Upgrading from 1.x?
instanceUserMethodsis nowclient.InstanceUsers, and every method takes the instance GUID first. See Migrating to 2.0.
The examples assume a client created as shown in the Intro, and guid set to your instance GUID. The user and token types are in Agility.Management.Sdk.Models:
using Agility.Management.Sdk;
using Agility.Management.Sdk.Models;
Every method also takes an optional CancellationToken cancellationToken as its last parameter. The signatures below leave it out.
Instance user management and token management need an OAuth access token. The API refuses a Personal Access Token for these calls.
| Area | Personal Access Token | OAuth access token |
|---|---|---|
client.InstanceUsers | No | Yes |
client.PersonalAccessTokens | No | Yes |
See the Intro for how to sign in with OAuth and give the client a refresh token.
GetCurrentUserAsync returns the user the access token belongs to, with the instances they can reach. It's a server-level call, so it doesn't take an instance GUID. Use it to find the GUIDs of the instances a token can reach.
ServerUser me = await client.ServerUsers.GetCurrentUserAsync();
Console.WriteLine($"Signed in as {me.EmailAddress}");
foreach (var site in me.WebsiteAccess ?? [])
{
Console.WriteLine($"{site.WebsiteName}: {site.Guid}");
}
Signature: Task<ServerUser> GetCurrentUserAsync()
Access via client.InstanceUsers.
List every user of an instance.
List<WebsiteUser> users = await client.InstanceUsers.GetUsersAsync(guid);
foreach (var user in users)
{
Console.WriteLine($"{user.EmailAddress} - {user.FirstName} {user.LastName} (ID: {user.UserID})");
}
Signature: Task<List<WebsiteUser>> GetUsersAsync(string instanceGuid)
Add a user to an instance, or change an existing user's roles. The user is identified by email address.
InstanceUser user = await client.InstanceUsers.SaveUserAsync(guid, "editor@example.com",
[new InstanceRole { RoleID = editorRoleId }],
firstName: "Sam", lastName: "Lee");
Console.WriteLine($"Saved user ID: {user.UserID}");
The roles you pass replace the user's current roles. To add a role, include the roles the user already has as well. firstName and lastName are used for a new user.
Signature: Task<InstanceUser> SaveUserAsync(string instanceGuid, string emailAddress, IReadOnlyList<InstanceRole> roles, string? firstName = null, string? lastName = null)
Remove a user from an instance by their user ID.
await client.InstanceUsers.DeleteUserAsync(guid, user.UserID);
The method returns nothing. If the delete fails, it throws an AgilityManagementException.
Signature: Task DeleteUserAsync(string instanceGuid, int userId)
client.PersonalAccessTokens manages your own Personal Access Tokens (PATs): long-lived tokens for scripts, CI and server-side jobs. These are server-level calls, so they don't take an instance GUID. They need an OAuth access token: a PAT can't create, list or revoke tokens.
For what a PAT is and how to use one, see Personal Access Tokens.
PersonalAccessTokenCreationResponse created = await client.PersonalAccessTokens.CreateTokenAsync(
new PersonalAccessTokenRequest
{
Name = "nightly-sync",
ExpiryDate = DateTime.UtcNow.AddYears(1),
});
StoreSecret(created.Token!); // the token value is returned only now
Name is required. ExpiryDate is optional: it can be at most two years away, and two years is the default.
⚠️ Store the token value straight away.
created.Tokenis the only time the API returns it. Listing or reading a token later never includes its value.
Signature: Task<PersonalAccessTokenCreationResponse> CreateTokenAsync(PersonalAccessTokenRequest request)
PersonalAccessTokenListResponse mine = await client.PersonalAccessTokens.GetTokensAsync();
foreach (var token in mine.Tokens ?? [])
{
Console.WriteLine($"{token.Name}: expires {token.ExpiryDate:d}, enabled: {token.Enabled}");
}
The list doesn't include token values.
Signature: Task<PersonalAccessTokenListResponse> GetTokensAsync()
PersonalAccessTokenResponse token = await client.PersonalAccessTokens.GetTokenAsync(tokenId);
Console.WriteLine($"{token.Name}: {token.DaysUntilExpiration} days left, last used {token.LastUsedDate}");
Signature: Task<PersonalAccessTokenResponse> GetTokenAsync(Guid tokenId)
Both properties of PersonalAccessTokenUpdateRequest are optional: set Name to rename the token, Enabled to turn it on or off, or both. The method returns the updated token.
await client.PersonalAccessTokens.UpdateTokenAsync(created.TokenID,
new PersonalAccessTokenUpdateRequest { Enabled = false });
Signature: Task<PersonalAccessTokenResponse> UpdateTokenAsync(Guid tokenId, PersonalAccessTokenUpdateRequest request)
await client.PersonalAccessTokens.RevokeTokenAsync(created.TokenID);
Signature: Task RevokeTokenAsync(Guid tokenId)
The API allows each user 10 active tokens, and 5 token creations an hour. Beyond that, it returns HTTP 429, which the SDK throws as an AgilityManagementException. The SDK doesn't retry a token creation, because it never retries writes.
client.OAuth returns an instance's Fetch API keys: one for published content and one for preview (staging) content. Use them to configure a website that reads content with the Fetch API.
string fetchKey = await client.OAuth.GetFetchApiKeyAsync(guid);
string previewKey = await client.OAuth.GetPreviewApiKeyAsync(guid);
Signatures:
Task<string> GetFetchApiKeyAsync(string instanceGuid)Task<string> GetPreviewApiKeyAsync(string instanceGuid)⚠️ Treat these keys as secrets. Don't log them or commit them.
Every error from the API or the network throws an AgilityManagementException. It carries the HTTP status code, the API's own message and a request ID. A call made with a Personal Access Token to an endpoint that needs OAuth fails this way too.
try
{
var users = await client.InstanceUsers.GetUsersAsync(guid);
}
catch (AgilityManagementException ex)
{
Console.Error.WriteLine($"{ex.StatusCode}: {ex.ApiMessage} (request {ex.RequestId})");
}
See the Intro for the full list of exceptions and the retry rules.
1.x (client.instanceUserMethods) | 2.0 (client.InstanceUsers) |
|---|---|
GetUsers(guid) | GetUsersAsync(guid) |
SaveUser(email, roles, guid, firstName, lastName) | SaveUserAsync(guid, email, roles, firstName, lastName) |
DeleteUser(userID, guid) | DeleteUserAsync(guid, userId): returns Task instead of a message string |
The signed-in user, Personal Access Token management and Fetch API keys are new in 2.0.