Find the insights and best practices about our product.
Users, Roles & Access Management

These endpoints manage tenant users and provide read access to roles, permissions, authentication settings, and API clients. POST /api/public/users is the only write endpoint on the Public API; every other endpoint here is read-only. All endpoints are tenant-scoped: a request only returns users, roles, settings, and clients belonging to the tenant that issued the token.

List Users

Returns a paginated list of users in your tenant, ordered by creation date with the oldest user first.

Request:

GET /api/public/users

Authentication:

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_Users_Read

Query Parameters

Response Fields

Sample Response

json

{
"data": [
{
"userId": 2141,
"firstName": "Ada",
"lastName": "Lovelace",
"email": "[email protected]",
"state": "Active",
"mfaStatus": true,
"mfaAction": true,
"roleId": null,
"roleName": "Tenant Admin",
"createdAt": "2025-11-03T14:22:00Z"
}
],
"pagination": {
"limit": 50,
"nextCursor": "eyJwYWdlTnVtYmVyIjoxfQ==",
"hasMore": true
},
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-08-13T10:00:00Z"
}
}


Users are ordered by creation date, oldest first, so a client that has caught up keeps its position and picks up new users on the next poll rather than seeing existing rows shift. A malformed or invalid cursor is rejected with a 400 error rather than falling back silently to the first page.

Error Responses

  • 400 BAD_REQUEST: cursor and updatedAfter were supplied together.
  • 400 VALIDATION_FAILED: the cursor is malformed or invalid.
  • 401 UNAUTHORIZED: the request is missing a token or the token lacks Api_Users_Read.
  • 500 INTERNAL_ERROR: an unexpected server error.


Get a User

Returns a single user by ID within your tenant.

Request

GET /api/public/users/{id}

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_Users_Read


{id} is the userId returned by GET /api/public/users. Not paginated; pagination is null. The response fields are the same as the list endpoint, with roleId populated.

Sample Response
{
"data": {
"userId": 2141,
"firstName": "Ada",
"lastName": "Lovelace",
"email": "[email protected]",
"state": "Active",
"mfaStatus": true,
"mfaAction": true,
"roleId": 12,
"roleName": "Tenant Admin",
"createdAt": "2025-11-03T14:22:00Z"
},
"pagination": null,
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-08-13T10:05:00Z"
}
}


This is the only way to retrieve a user's roleId through the Public API; the list endpoint always returns null for this field. A user belonging to more than one tenant has a role per tenant, and only the calling tenant's role is returned.

Error Responses

  • 404 NOT_FOUND: the user does not exist, or belongs to a different tenant. The two cases are indistinguishable by design.
  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_Users_Read.
  • 500 INTERNAL_ERROR: an unexpected server error.


Create a User

Creates a user in your tenant with exactly one role assigned. This is the only write endpoint on the Public API.

Request

POST /api/public/users

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_Users_Create. This is a separate permission from Api_Users_Read; a read-only client cannot create users.

Request Body: All Fields Required

Sample Request

{
"firstName": "Grace",
"lastName": "Hopper",
"email": "[email protected]",
"roleId": 12
}

Sample Response (201 Created)

{
"data": {
"userId": 2288,
"firstName": "Grace",
"lastName": "Hopper",
"email": "[email protected]",
"state": "Invited",
"mfaStatus": false,
"mfaAction": true,
"roleId": 12,
"roleName": "Security Analyst",
"createdAt": "2026-08-13T10:10:00Z"
},
"pagination": null,
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-08-13T10:10:00Z"
}
}


The new user is created in an Invited state. An invitation is sent, and the account activates once the user completes enrollment. This endpoint is not idempotent and has no request-deduplication key: if a request times out and you retry it, a 409 CONFLICT response may mean the first attempt actually succeeded. Treat it as "already created" rather than a failure.

Error Responses

  • 409 CONFLICT: a user with this email address already exists in your tenant.
  • 422 VALIDATION_FAILED: a field is missing, out of length, not a valid email, or roleId is missing, not greater than 0, or does not match a role in your tenant.
  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_Users_Create.
  • 500 INTERNAL_ERROR: an unexpected server error.



List Roles

Returns every role in your tenant, along with each role's assigned permissions.

Request

GET /api/public/roles

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_Roles_Read


Not paginated. pagination is null; the full list is returned in data.

Response Fields

Sample Response

{
"data": [
{
"roleId": 12,
"name": "Tenant Admin",
"description": "Full administrative access within the tenant",
"state": "Active",
"type": "User",
"isReadOnly": true,
"permissions": [
{
"permissionId": 269,
"name": "Read",
"module": "API",
"function": "Users",
"code": "Api_Users_Read"
}
]
}
],
"pagination": null,
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-08-13T10:15:00Z"
}
}


Only roles with type: "User" are valid for the roleId field on POST /api/public/users. Inactive roles are returned; filter on state if you only want assignable roles. No ordering is guaranteed, so sort client-side if you need a stable order.

Error Responses

  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_Roles_Read.
  • 500 INTERNAL_ERROR: an unexpected server error, including an upstream failure. This endpoint returns an error rather than an empty list when role data cannot be retrieved, so an empty data array always means your tenant genuinely has no roles.



Get a Role

Returns a single role by ID, scoped to your tenant.

Request

GET /api/public/roles/{id}

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_Roles_Read


{id} is the roleId returned by GET /api/public/roles. Not paginated. The response is the same shape as the list endpoint. If you need several roles, prefer one call to GET /api/public/roles over multiple calls to this endpoint.

Error Responses

  • 404 NOT_FOUND: the roles does not exist, or belongs to a different tenant.
  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_Roles_Read.
  • 500 INTERNAL_ERROR: an unexpected server error.



List Permissions

Returns the catalog of permissions that can be assigned to roles.

Request

GET /api/public/permissions

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_Roles_Read


Not paginated.

Response Fields

Sample Response

{
"data": [
{
"permissionId": 269,
"name": "Read",
"module": "API",
"function": "Users",
"code": "Api_Users_Read"
}
],
"pagination": null,
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-08-13T10:25:00Z"
}
}


This catalog may include permissions that do not yet gate any endpoint. Ordering is not guaranteed; sort client-side if you need a stable order.

Error Responses

  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_Roles_Read.
  • 500 INTERNAL_ERROR: an unexpected server error, including an upstream failure. As with roles, an empty data array always means your tenant genuinely has no assignable permissions.



Get Authentication Settings

Returns your tenant's authentication configuration: SSO settings and multi-factor authentication policy.

Request

GET /api/public/authentication-settings

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_AuthSettings_Read


Not paginated. data is a single object.

Response Fields

Sample Response: SSO Configured

{
"data": {
"ssoEnabled": true,
"ssoEnforced": false,
"providerType": "AzureAD",
"tenantName": "contoso",
"mfaEnabled": true
},
"pagination": null,
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-08-13T10:30:00Z"
}
}

Sample Response: No SSO Configured

{
"data": {
"ssoEnabled": false,
"ssoEnforced": false,
"providerType": null,
"tenantName": null,
"mfaEnabled": false
},
"pagination": null,
"error": null,
"meta": {
"requestId": "7b8c9d0e-1f2a-4b3c-9d4e-5f6a7b8c9d0e",
"timestamp": "2026-08-13T10:30:01Z"
}
}


A tenant without SSO configured returns 200 with these defaults, not an error. mfaEnabled is the tenant-wide policy, not a per-user state; combine it with GET /api/public/users to find users who have not yet enrolled under an enforcing policy.

Error Responses

  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_AuthSettings_Read.
  • 500 INTERNAL_ERROR: an unexpected server error.



List API Clients

Returns metadata for the API clients registered in your tenant, including the client you are using to make this request.

Request

GET /api/public/api-clients

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_ApiClients_Read

Query Parameters

Response Fields

Sample Response

{
"data": [
{
"clientId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"name": "ServiceNow connector",
"roleName": "Default API Role",
"secretExpirationDate": "2027-07-17T00:00:00Z",
"createdAt": "2026-07-17T10:00:00Z"
}
],
"pagination": {
"nextCursor": "cDox",
"hasMore": true
},
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-08-13T10:35:00Z"
}
}


Client secrets are never returned by this or any endpoint; a secret is shown once, at create, in the portal. secretExpirationDate is the main reason to poll this endpoint. Alert ahead of expiry so a client's secret doesn't lapse without warning. A malformed or invalid cursor is ignored and the first page is returned, rather than rejected, which differs from GET /api/public/users. An empty data array with hasMore: false can mean either that your tenant has no API clients or that the request could not be completed; re-poll to confirm before treating an empty result as authoritative.

Error Responses

  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_ApiClients_Read.
  • 500 INTERNAL_ERROR: an unexpected server error.
Did this answer your question?