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
Parameter | Type | Value |
|---|---|---|
| integer | Results per page. Default 50, maximum 200. |
| string | Opaque page token. Omit on the first call. Pass |
| ISO 8601 timestamp | Resets the feed to the first page. Does not filter by date on this endpoint. Cannot be combined with |
Response Fields
Field | Type | Value |
|---|---|---|
| integer | Unique identifier for the user. |
| string | User's first name. |
| string | User's last name. |
| string | User's email address. |
| string |
|
| boolean or null | Whether the user has enrolled in multi-factor authentication. |
| boolean or null | Whether tenant policy enforces multi-factor authentication for this user. |
| integer or null | Always |
| string or null | The user's role name. |
| ISO 8601 timestamp | When the user was created. |
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:cursorandupdatedAfterwere supplied together.400 VALIDATION_FAILED: the cursor is malformed or invalid.401 UNAUTHORIZED: the request is missing a token or the token lacksApi_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 lacksApi_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
Field | Type | Rules |
|---|---|---|
| string | 1-255 characters. |
| string | 1-255 characters. |
| string | 1-255 characters. Must be a valid email address. |
| integer | Must be greater than 0 and must match a role in your tenant. Discover valid values with |
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, orroleIdis 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 lacksApi_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
Field | Type | Rules |
|---|---|---|
| integer | Unique identifier for the role. |
| string | Role name. |
| string | Role description. |
| integer |
|
| integer |
|
| boolean | Whether this is a built-in role that cannot be modified. |
| array | The permissions assigned to this role, in the same shape as |
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 lacksApi_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 emptydataarray 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 lacksApi_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
Field | Type | Rules |
|---|---|---|
| integer | Unique identifier for the permission. |
| string | Action name, e.g. |
| string | Grouping, e.g. |
| integer | The area the permission applies to, e.g. |
| integer | The stable identifier for the permission, e.g. |
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 lacksApi_Roles_Read.500 INTERNAL_ERROR: an unexpected server error, including an upstream failure. As with roles, an emptydataarray 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
Field | Type | Rules |
|---|---|---|
| boolean | Whether SSO is configured for the tenant. |
| boolean | Whether users must authenticate via SSO. Check this together with |
| string or null | The identity provider, e.g. |
| string or null | The tenant identifier registered with the SSO provider. |
| boolean | The tenant-wide multi-factor authentication policy. Corresponds to |
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 lacksApi_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
Parameter | Type | Value |
|---|---|---|
| integer | Results per page. Default 50, maximum 200. This endpoint uses |
| string | Opaque page token from the previous response. Omit on the first call |
Response Fields
Field | Type | Rules |
|---|---|---|
| string | Public identifier for the client. Not a credential; safe to log. |
| string | Client name. |
| string | The API role attached to this client. |
| integer | When the client's secret expires. |
| integer | When the client was created. |
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 lacksApi_ApiClients_Read.500 INTERNAL_ERROR: an unexpected server error.





