Agility CMS documentationAgility CMS documentation
OverviewEditorsDevelopersOwners & AdminsTraining GuideApps
Sign inLet's Chat
Management SDK
Instance & Users

Instance

Instance & Users

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.

Instance users

Access via apiClient.instanceUserMethods (JavaScript) or client.instanceUserMethods (.NET).

OperationJavaScript.NET
List all users on the instancegetUsers(guid)GetUsers(guid)
Create a user or update their rolessaveUser(...)SaveUser(...)
Remove a user from the instancedeleteUser(userID, guid)DeleteUser(userID, guid)

Get users

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)

Save user

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)

ParameterTypeDescription
emailAddressstringThe user's email address. Used as the match key for existing users.
rolesInstanceRole[] / List<InstanceRole>The roles to assign on this instance, e.g. Editor.
guidstringThe instance GUID.
firstNamestring, optionalThe user's first name.
lastNamestring, optionalThe user's last name.

Delete user

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)


Locales

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:

FieldTypeDescription
localeIDnumberInternal identifier, used by the enable/disable endpoints.
localeNamestringDisplay name, e.g. English (United States).
localeCodestringThe code you pass as locale everywhere else, e.g. en-us.
enabledbooleanWhether content can be authored in this locale.
custombooleanWhether it's a custom locale rather than a standard one.
sortOrdernumberPosition 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.

Managing locales over REST

There's no SDK wrapper for these yet — call them directly with the same bearer token:

OperationEndpoint
List localesGET /api/v1/instance/{guid}/locales
List enabled and disabled localesGET /api/v1/instance/{guid}/locales/all
Get one locale by IDGET /api/v1/instance/{guid}/locales/{localeId}
Get one locale by codeGET /api/v1/instance/{guid}/locales/code/{localeCode}
Add a localePOST /api/v1/instance/{guid}/locales
Reorder localesPOST /api/v1/instance/{guid}/locales/sort-order
Enable a localePATCH /api/v1/instance/{guid}/locales/{localeId}/enable
Disable a localePATCH /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,
  });
}

Current user

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.


Fetch API sync status

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.

FieldDescription
inProgressWhether a sync is running right now.
itemsAffectedNumber of items in the sync.
startTime / completionTimeWhen the sync started and finished.
errorMessageSet if the sync failed.
pushType1 = Preview, 2 = Fetch/Live.
lastContentVersionIDLast content version synced — compare against a save's version to confirm it landed.
lastDeletedContentVersionIDLast deleted content version synced.
lastDeletedPageVersionIDLast deleted page version synced.
maxChangeDateMost recent change date processed.
maxContentModelDateMost recent model change processed.
leaseIDLease identifier for the sync operation.
websiteNameThe instance's website name.
timestampWhen this status record was written.

JavaScript SDK only. From .NET, call GET /api/v1/instance/{guid}/fetch-api-status?mode=fetch (mode accepts fetch or preview).

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');
}

Retrieving API keys programmatically

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.

KeyEndpoint
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.


Enum values reference

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:

NameValue
New-1
None0
Staging1
Published2
Deleted3
Approved4
AwaitingApproval5
Declined6
Unpublished7

workflowOperationTypes — the operation argument for batch workflow calls:

NameValue
Publish1
Unpublish2
Approve3
Decline4
RequestApproval5

contentModelTypes — the model type on a container:

NameValue
Item0
List1
Module2

contentViewTypes — the contentType filter for paged container listings:

NameValue
All0
Shared1
Linked2
DynamicPageList3

batchStates — progress of a batch operation:

NameValue
None0
Pending1
InProcess2
Processed3
Deleted4

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

Error handling

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}");
}
On this page
Instance usersLocalesCurrent userFetch API sync statusRetrieving API keys programmaticallyEnum values referenceError handling
Agility CMS documentationAgility CMS documentation

Documentation for the CMS built for editors, developers, and AI agents.

Docs
  • Overview
  • Editors
  • Developers
  • Owners & Admins
  • Training Guide
  • Changelog
Resources
  • Get Support
  • MCP Server
  • System Status
  • llms.txt
Agility
  • agilitycms.com
  • Start Free Trial
  • Sign in
  • Blog
© 2026 Agility Inc. All rights reserved.
Privacy PolicyTerms of Service