Instance
Manage instance users and roles, read and enable locales, check Fetch API sync status, retrieve API keys, and look up every Management API enum value.
The Management SDK exposes instance-level operations: the users who have access to an instance, the locales configured on it, the currently authenticated user, and whether your recent changes have reached the Fetch API yet.
Instance users are managed through the instanceUserMethods group, available in both SDKs. Locales, the current user, and Fetch API status are JavaScript-only in the SDK — but every one of them has a REST endpoint, so nothing is out of reach from .NET. Each section below gives the endpoint.
Every method takes the instance guid so a single authenticated client can operate across multiple instances.
Access via apiClient.instanceUserMethods (JavaScript) or client.instanceUserMethods (.NET).
| Operation | JavaScript | .NET |
|---|---|---|
| List all users on the instance | getUsers(guid) | GetUsers(guid) |
| Create a user or update their roles | saveUser(...) | SaveUser(...) |
| Remove a user from the instance | deleteUser(userID, guid) | DeleteUser(userID, guid) |
Retrieve all users who have access to the instance.
const users = await apiClient.instanceUserMethods.getUsers(guid);
console.log(users);
var users = await client.instanceUserMethods.GetUsers(guid);
foreach (var user in users)
{
Console.WriteLine($"{user.EmailAddress} - {user.FirstName} {user.LastName}");
}
.NET signature: Task<List<WebsiteUser?>> GetUsers(string guid)
Create a user or update an existing one. If the email address already exists on the instance, the user's roles are updated rather than a new user being created.
const savedUser = await apiClient.instanceUserMethods.saveUser(
'user@example.com',
[/* InstanceRole[] */],
guid,
'First',
'Last'
);
using agility.models;
var roles = new List<InstanceRole>
{
new InstanceRole { RoleName = "Editor" }
};
var savedUser = await client.instanceUserMethods.SaveUser(
emailAddress: "user@example.com",
roles: roles,
guid: guid,
firstName: "Jane",
lastName: "Doe"
);
Console.WriteLine($"Saved user ID: {savedUser?.UserID}");
.NET signature: Task<InstanceUser?> SaveUser(string? emailAddress, List<InstanceRole> roles, string guid, string? firstName = null, string? lastName = null)
| Parameter | Type | Description |
|---|---|---|
emailAddress | string | The user's email address. Used as the match key for existing users. |
roles | InstanceRole[] / List<InstanceRole> | The roles to assign on this instance, e.g. Editor. |
guid | string | The instance GUID. |
firstName | string, optional | The user's first name. |
lastName | string, optional | The user's last name. |
Remove a user from the instance by their user ID.
const deletedUser = await apiClient.instanceUserMethods.deleteUser(1234, guid);
var result = await client.instanceUserMethods.DeleteUser(userId, guid);
Console.WriteLine($"Delete result: {result}");
.NET signature: Task<string?> DeleteUser(int? userID, string guid)
The SDK gives you a read; the API gives you the full set of locale operations.
// Get the locales configured for an instance
const locales = await apiClient.instanceMethods.getLocales(guid);
console.log(locales);
JavaScript SDK only. From .NET, call
GET /api/v1/instance/{guid}/locales.
Each locale looks like this:
| Field | Type | Description |
|---|---|---|
localeID | number | Internal identifier, used by the enable/disable endpoints. |
localeName | string | Display name, e.g. English (United States). |
localeCode | string | The code you pass as locale everywhere else, e.g. en-us. |
enabled | boolean | Whether content can be authored in this locale. |
custom | boolean | Whether it's a custom locale rather than a standard one. |
sortOrder | number | Position in the CMS locale switcher. |
The SDK types this return value loosely, so treat the result as the endpoint's own JSON rather than relying on the declared type.
There's no SDK wrapper for these yet — call them directly with the same bearer token:
| Operation | Endpoint |
|---|---|
| List locales | GET /api/v1/instance/{guid}/locales |
| List enabled and disabled locales | GET /api/v1/instance/{guid}/locales/all |
| Get one locale by ID | GET /api/v1/instance/{guid}/locales/{localeId} |
| Get one locale by code | GET /api/v1/instance/{guid}/locales/code/{localeCode} |
| Add a locale | POST /api/v1/instance/{guid}/locales |
| Reorder locales | POST /api/v1/instance/{guid}/locales/sort-order |
| Enable a locale | PATCH /api/v1/instance/{guid}/locales/{localeId}/enable |
| Disable a locale | PATCH /api/v1/instance/{guid}/locales/{localeId}/disable |
/locales/all returns two arrays, enabledLocales and disabledLocales, which is the call you want when building a locale-management UI.
There is no delete. Locales are enabled and disabled, never removed — which is the right design, since deleting one would orphan every piece of content authored in it. Disabling hides a locale from authoring without touching the content already there.
async function enableLocale(guid: string, localeCode: string, token: string) {
const base = 'https://mgmt.aglty.io/api/v1/instance';
const headers = { Authorization: `Bearer ${token}` };
const all = await fetch(`${base}/${guid}/locales/all`, { headers }).then(r => r.json());
const match = all.disabledLocales?.find(l => l.localeCode === localeCode);
if (!match) {
console.log(`${localeCode} is not in the disabled list — already enabled, or not added yet`);
return;
}
await fetch(`${base}/${guid}/locales/${match.localeID}/enable`, {
method: 'PATCH',
headers,
});
}
Get the currently authenticated user along with all of their instance access details — useful for confirming which instances a token can actually reach.
const user = await apiClient.serverUserMethods.me(guid);
JavaScript SDK only. From .NET, call
GET /api/v1/users/me.
Pass your real
guid, even though the endpoint isn't instance-scoped. The SDK uses the GUID's regional suffix to choose which API host to call. Hand it an empty string and it falls back to the default region, which returns nothing useful if your instance lives in Canada, Europe, or Australia.
This one solves a real timing problem. The Management API writes to the CMS, but content is served from the Fetch API's CDN, and there's a propagation delay between the two. If a deploy script publishes content and then immediately rebuilds a site, it can build against content that hasn't landed yet.
getFetchApiStatus tells you where that sync is:
// mode: 'fetch' for the live CDN, 'preview' for the preview CDN
const status = await apiClient.instanceMethods.getFetchApiStatus(guid, 'fetch');
if (status.inProgress) {
console.log(`Sync running since ${status.startTime}, ${status.itemsAffected} items affected`);
} else {
console.log(`Last sync completed ${status.completionTime}`);
}
Signature: getFetchApiStatus(guid: string, mode?: FetchApiSyncMode, waitForCompletion?: boolean): Promise<FetchApiStatus>
Pass waitForCompletion: true to have the SDK poll until the sync finishes rather than returning the current snapshot — the polling interval and attempt cap come from the duration and retryCount fields on Options.
| Field | Description |
|---|---|
inProgress | Whether a sync is running right now. |
itemsAffected | Number of items in the sync. |
startTime / completionTime | When the sync started and finished. |
errorMessage | Set if the sync failed. |
pushType | 1 = Preview, 2 = Fetch/Live. |
lastContentVersionID | Last content version synced — compare against a save's version to confirm it landed. |
lastDeletedContentVersionID | Last deleted content version synced. |
lastDeletedPageVersionID | Last deleted page version synced. |
maxChangeDate | Most recent change date processed. |
maxContentModelDate | Most recent model change processed. |
leaseID | Lease identifier for the sync operation. |
websiteName | The instance's website name. |
timestamp | When this status record was written. |
JavaScript SDK only. From .NET, call
GET /api/v1/instance/{guid}/fetch-api-status?mode=fetch(modeacceptsfetchorpreview).
Wait for a publish to go live before rebuilding:
async function waitForSync(guid: string, timeoutMs = 120_000) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const status = await apiClient.instanceMethods.getFetchApiStatus(guid, 'fetch');
if (status.errorMessage) {
throw new Error(`Fetch API sync failed: ${status.errorMessage}`);
}
if (!status.inProgress) {
return status;
}
await new Promise(r => setTimeout(r, 3000));
}
throw new Error('Timed out waiting for the Fetch API sync');
}
The Fetch and Preview API keys are visible in the Agility UI, but you can also read them with an authenticated Management API call — handy when provisioning environments or seeding CI secrets rather than copying keys by hand.
| Key | Endpoint |
|---|---|
| Fetch (live content) | GET /oauth/getfetchkey?guid={guid} |
| Preview (staged content) | GET /oauth/getpreviewkey?guid={guid} |
Both return the key as a plain string and both require a valid Management API bearer token.
async function getApiKeys(guid: string, token: string) {
const headers = { Authorization: `Bearer ${token}` };
const [fetchKey, previewKey] = await Promise.all([
fetch(`https://mgmt.aglty.io/oauth/getfetchkey?guid=${guid}`, { headers }).then(r => r.text()),
fetch(`https://mgmt.aglty.io/oauth/getpreviewkey?guid=${guid}`, { headers }).then(r => r.text()),
]);
return { fetchKey, previewKey };
}
These are secrets. The preview key in particular exposes unpublished content. Write them straight into your secret store — never into logs, build output, or anything client-side.
The Management API's numeric enums — the ones behind properties.state, workflow operations, container types — are published at a single endpoint:
GET https://mgmt.aglty.io/api/v1/types
It needs no authentication and no instance GUID, so you can open it in a browser. Each entry gives a name, its numeric value, and an optional description. When a value in this documentation disagrees with that endpoint, the endpoint is right.
The ones you'll reach for most:
itemStates — what properties.state means on a content item or page:
| Name | Value |
|---|---|
New | -1 |
None | 0 |
Staging | 1 |
Published | 2 |
Deleted | 3 |
Approved | 4 |
AwaitingApproval | 5 |
Declined | 6 |
Unpublished | 7 |
workflowOperationTypes — the operation argument for batch workflow calls:
| Name | Value |
|---|---|
Publish | 1 |
Unpublish | 2 |
Approve | 3 |
Decline | 4 |
RequestApproval | 5 |
contentModelTypes — the model type on a container:
| Name | Value |
|---|---|
Item | 0 |
List | 1 |
Module | 2 |
contentViewTypes — the contentType filter for paged container listings:
| Name | Value |
|---|---|
All | 0 |
Shared | 1 |
Linked | 2 |
DynamicPageList | 3 |
batchStates — progress of a batch operation:
| Name | Value |
|---|---|
None | 0 |
Pending | 1 |
InProcess | 2 |
Processed | 3 |
Deleted | 4 |
The same response also carries modes, pageTypes, pageItemTemplateTypes, batchItemTypes, batchOperationTypes, instancePermissions, userTypes, assetGroupingTypes, notificationTypes, changeItemTypes, and changeTypes. Rather than hard-coding any of these, read them once at startup:
const types = await fetch('https://mgmt.aglty.io/api/v1/types').then(r => r.json());
const itemState = Object.fromEntries(
types.itemStates.map((e: { name: string; value: number }) => [e.name, e.value])
);
console.log(itemState.Published); // 2
In the .NET SDK, all instanceUserMethods calls throw ApplicationException on failure.
try
{
var users = await client.instanceUserMethods.GetUsers(guid);
}
catch (ApplicationException ex)
{
Console.Error.WriteLine($"Failed: {ex.Message}");
}