API reference
Tenant: users, groups, roles and policies
/ v1/ orgs/ :orgId/ tenant/ groupsGroups with their size, owners and the roles they grant.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
groups: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}[]
}/ v1/ orgs/ :orgId/ tenant/ groupsCreates a group; owners default to the person creating it. role is a built-in role members get (not owner).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
namestringrequired1–64 characters. Trimmed.
slugstringUp to 39 characters. Trimmed.
descriptionstringUp to 500 characters. Trimmed.
role"admin" | "developer" | "viewer"customRoleIdsstring[]Up to 20 items. Each up to 40 characters.
ownerIdsstring[]Up to 20 items. Each up to 64 characters.
Errors
400Slugs are lowercase letters, digits and single hyphens.400Unknown role.404Organization not found404Not a member of this organization404Group not found409A group with this slug exists.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Example"
}'Response 201
{
group: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}
members: {
userId: string
email?: string
name?: string
role: "owner" | "member"
addedAt?: number
}[]
grants: {
level: "write"
type: "project"
id: string
name: string
} | {
level: "write"
type: "repository"
id: string
name: string
}[]
apps: string[]
}/ v1/ orgs/ :orgId/ tenant/ groups/ :teamIdMembers, owners, granted roles, Serverless App Service and repository access, and app assignments.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).teamIdGroup id (
team_…).
Errors
404Group not found
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups/{teamId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
group: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}
members: {
userId: string
email?: string
name?: string
role: "owner" | "member"
addedAt?: number
}[]
grants: {
level: "write"
type: "project"
id: string
name: string
} | {
level: "write"
type: "repository"
id: string
name: string
}[]
apps: string[]
}/ v1/ orgs/ :orgId/ tenant/ groups/ :teamIdName, description, the built-in role members get (null removes it) and custom roles.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).teamIdGroup id (
team_…).
Request body
namestring1–64 characters. Trimmed.
descriptionstringor nullUp to 500 characters. Trimmed.
role"admin" | "developer" | "viewer"or nullcustomRoleIdsstring[]Up to 20 items. Each up to 40 characters.
Errors
400Unknown role.404Organization not found404Group not found
curl -X PATCH 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups/{teamId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Example",
"description": "example",
"role": "admin"
}'Response 200
{
group: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}
members: {
userId: string
email?: string
name?: string
role: "owner" | "member"
addedAt?: number
}[]
grants: {
level: "write"
type: "project"
id: string
name: string
} | {
level: "write"
type: "repository"
id: string
name: string
}[]
apps: string[]
}/ v1/ orgs/ :orgId/ tenant/ groups/ :teamIdDeletes the group with its memberships, access and assignments (members keep their own roles).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).teamIdGroup id (
team_…).
Errors
404Organization not found404Group not found
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups/{teamId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenant/ groups/ :teamId/ members/ :userIdAdds a member or changes their group role (owner manages the group's members, member).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).teamIdGroup id (
team_…).userIdA member's user id (
usr_…).
Request body
role"owner" | "member"Default
"member".
Errors
404Organization not found404Group not found404Not a member of this organization
curl -X PUT 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups/{teamId}/members/{userId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"role": "member"
}'Response 200
{
group: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}
members: {
userId: string
email?: string
name?: string
role: "owner" | "member"
addedAt?: number
}[]
grants: {
level: "write"
type: "project"
id: string
name: string
} | {
level: "write"
type: "repository"
id: string
name: string
}[]
apps: string[]
}/ v1/ orgs/ :orgId/ tenant/ groups/ :teamId/ members/ :userIdTakes a member out of the group.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).teamIdGroup id (
team_…).userIdA member's user id (
usr_…).
Errors
404Organization not found404Group not found404Not a member of this organization
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups/{teamId}/members/{userId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
group: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}
members: {
userId: string
email?: string
name?: string
role: "owner" | "member"
addedAt?: number
}[]
grants: {
level: "write"
type: "project"
id: string
name: string
} | {
level: "write"
type: "repository"
id: string
name: string
}[]
apps: string[]
}/ v1/ orgs/ :orgId/ tenant/ groups/ :teamId/ grants/ :resourceType/ :resourceIdGives the group write access to one Serverless App Service or repository.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).teamIdGroup id (
team_…).resourceTypeWhat the protocol is attached to:
org,project,space,calendar,mailboxoragent; for a group's access,projectorrepository.resourceIdResource id (
res_…); for a group's access, the Serverless App Service id (prj_…) or the repository's resource id.
Errors
400Unknown resource type or principal.400Unknown resource.404Group not found404That Serverless App Service or repository isn't in this organization.
curl -X PUT 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups/{teamId}/grants/{resourceType}/{resourceId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
group: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}
members: {
userId: string
email?: string
name?: string
role: "owner" | "member"
addedAt?: number
}[]
grants: {
level: "write"
type: "project"
id: string
name: string
} | {
level: "write"
type: "repository"
id: string
name: string
}[]
apps: string[]
}/ v1/ orgs/ :orgId/ tenant/ groups/ :teamId/ grants/ :resourceType/ :resourceIdRemoves the group's write access to the Serverless App Service or repository.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).teamIdGroup id (
team_…).resourceTypeWhat the protocol is attached to:
org,project,space,calendar,mailboxoragent; for a group's access,projectorrepository.resourceIdResource id (
res_…); for a group's access, the Serverless App Service id (prj_…) or the repository's resource id.
Errors
400Unknown resource type or principal.400Unknown resource.404Group not found404That Serverless App Service or repository isn't in this organization.
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/groups/{teamId}/grants/{resourceType}/{resourceId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
group: {
customRoleIds: string[]
members: number
owners: string[]
createdAt?: number
role?: "admin" | "developer" | "viewer"
description?: string
teamId: string
slug: string
name: string
}
members: {
userId: string
email?: string
name?: string
role: "owner" | "member"
addedAt?: number
}[]
grants: {
level: "write"
type: "project"
id: string
name: string
} | {
level: "write"
type: "repository"
id: string
name: string
}[]
apps: string[]
}/ v1/ orgs/ :orgId/ tenant/ rolesBuilt-in roles with their scopes, custom roles, and who holds each.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
Errors
404Organization not found
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/roles' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
builtIn: {
users: string[]
groups: string[]
scopes: ("platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write")[]
groupAssignable: boolean
id: "owner" | "admin" | "developer" | "viewer"
name: string
description: string
}[]
custom: {
users: string[]
groups: string[]
scopes: string[]
createdAt?: number
updatedAt?: number
description?: string
roleId: string
name: string
}[]
assignableScopes: ("platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write")[]
}/ v1/ orgs/ :orgId/ tenant/ rolesCreates a custom role: a named set of scopes added on top of a member's role.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
namestringrequired1–64 characters. Trimmed.
descriptionstringUp to 500 characters. Trimmed.
scopes[]required1–100 items.
Errors
400Unknown or platform scopes: …400Choose at least one scope.400An organization can have up to 50 custom roles.409A role with this name exists.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/roles' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Example",
"scopes": []
}'Response 201
{
role: {
name: string
createdAt?: number
updatedAt?: number
orgId: string
createdBy: string
scopes: string[]
description?: string
roleId: string
}
}/ v1/ orgs/ :orgId/ tenant/ roles/ :roleIdRenames a custom role or changes its scopes (you need every scope it grants, before and after).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).roleIdA built-in role (
owner,admin,developer,viewer) or a custom role id (rol_…); in Mirage, a server role (mrl_…, or the server's id for @everyone).
Request body
namestring1–64 characters. Trimmed.
descriptionstringor nullUp to 500 characters. Trimmed.
scopes[]1–100 items.
Errors
400Unknown or platform scopes: …400Choose at least one scope.404Role not found409A role with this name exists.
curl -X PATCH 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/roles/{roleId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Example",
"description": "example",
"scopes": []
}'Response 200
{
role: {
name: string
createdAt?: number
updatedAt?: number
orgId: string
createdBy: string
scopes: string[]
description?: string
roleId: string
}
}/ v1/ orgs/ :orgId/ tenant/ roles/ :roleIdDeletes a custom role; members and groups holding it lose its scopes.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).roleIdA built-in role (
owner,admin,developer,viewer) or a custom role id (rol_…); in Mirage, a server role (mrl_…, or the server's id for @everyone).
Errors
404Role not found
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/roles/{roleId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenant/ roles/ :roleId/ assignmentsAssigns a role (a built-in role id such as admin, or a custom rol_…) to a member or group. A built-in role replaces a member's role; a group grants one built-in role at most.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).roleIdA built-in role (
owner,admin,developer,viewer) or a custom role id (rol_…); in Mirage, a server role (mrl_…, or the server's id for @everyone).
Request body
principalType"user" | "group"requiredprincipalIdstringrequired1–64 characters.
Errors
400Guests can be developers or viewers.400Only guests have an access end date.400Groups can't grant the owner role.400Unknown role.404Organization not found404Not a member of this organization404Group not found404Role not found409An organization needs at least one other active owner first.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/roles/{roleId}/assignments' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"principalType": "user",
"principalId": "<principalId>"
}'Response 200
{
builtIn: {
users: string[]
groups: string[]
scopes: ("platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write")[]
groupAssignable: boolean
id: "owner" | "admin" | "developer" | "viewer"
name: string
description: string
}[]
custom: {
users: string[]
groups: string[]
scopes: string[]
createdAt?: number
updatedAt?: number
description?: string
roleId: string
name: string
}[]
assignableScopes: ("platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write")[]
}/ v1/ orgs/ :orgId/ tenant/ roles/ :roleId/ assignments/ :principalType/ :principalIdTakes a custom role from a member or group, or the built-in role a group grants.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).roleIdA built-in role (
owner,admin,developer,viewer) or a custom role id (rol_…); in Mirage, a server role (mrl_…, or the server's id for @everyone).principalTypeuserorgroup.principalIdA person (
usr_…) or a group or team (team_…): the member or group a Tenant assignment or a Drive share is for.
Errors
400Unknown resource type or principal.400Every member has a built-in role: assign another one instead.400Unknown role.404Group not found404Organization not found404Role not found404Not a member of this organization
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/roles/{roleId}/assignments/{principalType}/{principalId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
builtIn: {
users: string[]
groups: string[]
scopes: ("platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write")[]
groupAssignable: boolean
id: "owner" | "admin" | "developer" | "viewer"
name: string
description: string
}[]
custom: {
users: string[]
groups: string[]
scopes: string[]
createdAt?: number
updatedAt?: number
description?: string
roleId: string
name: string
}[]
assignableScopes: ("platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write")[]
}/ v1/ orgs/ :orgId/ tenant/ appsThe org's sign-in clients (per Serverless App Service) with assignment and secret expiry, MCP clients members connected here, and its keys.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/apps' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
signIn: {
createdAt?: number
lastUsedAt?: number
secretCreatedAt?: number
secretExpiresAt?: number
assignmentRequired: boolean
assignments: number
clientUri?: string
logoUri?: string
clientId: string
name: string
projectId?: string
project?: string
redirectUris: string[]
subjectType: "public" | "pairwise"
}[]
mcp: {
clientId: string
name: string
users: {
userId: string
scopes: string[]
lastUsedAt?: number
connectedAt?: number
}[]
}[]
keys: {
keyId: string
name: string
kind: "api" | "mcp" | "agent"
scopes: string[]
createdBy: string
lastUsedAt?: number
expiresAt?: number
createdAt?: number
machine: boolean
}[]
}/ v1/ orgs/ :orgId/ tenant/ apps/ :clientIdOne sign-in client: redirect URIs, secret expiry and who is assigned.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).clientIdSign-in client id (
cli_…).
Errors
404App not found
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/apps/{clientId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
app: {
createdAt?: number
lastUsedAt?: number
secretCreatedAt?: number
secretExpiresAt?: number
assignmentRequired: boolean
assignments: number
clientUri?: string
logoUri?: string
clientId: string
name: string
projectId?: string
project?: string
redirectUris: string[]
subjectType: "public" | "pairwise"
}
assignments: {
principalType: "user" | "group"
principalId: string
label: string
assignedAt?: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ apps/ :clientIdassignmentRequired: only assigned people and groups can sign in (checked at sign-in and every refresh).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).clientIdSign-in client id (
cli_…).
Request body
assignmentRequiredbooleanrequired
Errors
404App not found
curl -X PATCH 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/apps/{clientId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"assignmentRequired": true
}'Response 200
{
app: {
createdAt?: number
lastUsedAt?: number
secretCreatedAt?: number
secretExpiresAt?: number
assignmentRequired: boolean
assignments: number
clientUri?: string
logoUri?: string
clientId: string
name: string
projectId?: string
project?: string
redirectUris: string[]
subjectType: "public" | "pairwise"
}
assignments: {
principalType: "user" | "group"
principalId: string
label: string
assignedAt?: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ apps/ :clientId/ secretReplaces the secret (the old one stops at once) with one valid for expiresInDays (0: no expiry); shown once.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).clientIdSign-in client id (
cli_…).
Request body
expiresInDaysintegerDefault
180.
Errors
400Choose a lifetime from the list.404App not found
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/apps/{clientId}/secret' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"expiresInDays": 180
}'Response 200
{
secretExpiresAt?: number
clientSecret: string
app: {
createdAt?: number
lastUsedAt?: number
secretCreatedAt?: number
secretExpiresAt?: number
assignmentRequired: boolean
assignments: number
clientUri?: string
logoUri?: string
clientId: string
name: string
projectId?: string
project?: string
redirectUris: string[]
subjectType: "public" | "pairwise"
}
assignments: {
principalType: "user" | "group"
principalId: string
label: string
assignedAt?: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ apps/ :clientId/ assignmentsLets a member or group sign in to an app that requires assignment.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).clientIdSign-in client id (
cli_…).
Request body
principalType"user" | "group"requiredprincipalIdstringrequired1–64 characters.
Errors
404App not found404Not a member of this organization404Group not found
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/apps/{clientId}/assignments' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"principalType": "user",
"principalId": "<principalId>"
}'Response 200
{
app: {
createdAt?: number
lastUsedAt?: number
secretCreatedAt?: number
secretExpiresAt?: number
assignmentRequired: boolean
assignments: number
clientUri?: string
logoUri?: string
clientId: string
name: string
projectId?: string
project?: string
redirectUris: string[]
subjectType: "public" | "pairwise"
}
assignments: {
principalType: "user" | "group"
principalId: string
label: string
assignedAt?: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ apps/ :clientId/ assignments/ :principalType/ :principalIdTakes a member's or group's assignment away; their next refresh is refused.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).clientIdSign-in client id (
cli_…).principalTypeuserorgroup.principalIdA person (
usr_…) or a group or team (team_…): the member or group a Tenant assignment or a Drive share is for.
Errors
400Unknown resource type or principal.404App not found
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/apps/{clientId}/assignments/{principalType}/{principalId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
app: {
createdAt?: number
lastUsedAt?: number
secretCreatedAt?: number
secretExpiresAt?: number
assignmentRequired: boolean
assignments: number
clientUri?: string
logoUri?: string
clientId: string
name: string
projectId?: string
project?: string
redirectUris: string[]
subjectType: "public" | "pairwise"
}
assignments: {
principalType: "user" | "group"
principalId: string
label: string
assignedAt?: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ apps/ :clientId/ connectionsDisconnects an MCP client from this org for every member.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).clientIdSign-in client id (
cli_…).
Errors
404App not found
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/apps/{clientId}/connections' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenant/ app-accessEvery app the org can switch, with its access (everyone, groups, off), whether the plan has it and how many reach it; and the groups.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/app-access' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
apps: {
key: string
label: string
apps: string[]
appIds: string[]
access: "off" | "everyone" | "groups"
groupIds: string[]
inPlan: boolean
reach: number
}[]
groups: {
teamId: string
name: string
}[]
members: number
}/ v1/ orgs/ :orgId/ tenant/ app-access/ :keySets who reaches an app: { access: "everyone" | "groups" | "off", groupIds? }. Owners and admins, themselves; owners and admins always reach it.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).keyVariable name; under
marketingjourneys a person's key: their email address, mobile (E.164) orrec:<record id>, URL-encoded.
Request body
access"everyone" | "groups" | "off"requiredgroupIdsstring[]Up to 50 items. Each up to 64 characters.
Errors
400Choose everyone, chosen groups or off.400Choose at least one group.400Choose at most 50 groups.400Choose groups from this organisation.404That app can't be switched here.404Organization not found
curl -X PUT 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/app-access/{key}' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"access": "everyone"
}'Response 200
{
apps: {
key: string
label: string
apps: string[]
appIds: string[]
access: "off" | "everyone" | "groups"
groupIds: string[]
inPlan: boolean
reach: number
}[]
groups: {
teamId: string
name: string
}[]
members: number
}/ v1/ orgs/ :orgId/ tenant/ app-switcherEvery app the org can hide from the switcher (its apps, never Tenant), in the launcher's order, with whether it does.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/app-switcher' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
apps: {
key: string
label: string
hidden: boolean
}[]
}/ v1/ orgs/ :orgId/ tenant/ app-switcher/ :keyHides an app from everyone's switcher in the org ({ hidden: true }) or shows it again. Owners and admins, themselves; audited org_app.switcher.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).keyVariable name; under
marketingjourneys a person's key: their email address, mobile (E.164) orrec:<record id>, URL-encoded.
Request body
hiddenbooleanrequired
Errors
404That app can't be hidden here.404Organization not found
curl -X PUT 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/app-switcher/{key}' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"hidden": true
}'Response 200
{
apps: {
key: string
label: string
hidden: boolean
}[]
}/ v1/ orgs/ :orgId/ tenant/ sign-insMembers' sign-ins and failed sign-ins, newest first: method, address, approximate place, device.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
Query parameters
cursorstringUp to 4,096 characters.
limitintegerDefault
50. 1–100. Coerced from a string.userstringUp to 64 characters.
result"success" | "failure"
Errors
400Invalid cursor
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/sign-ins' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
signIns: {
eventId: string
at: number
userId: string
user?: string
result: "success" | "failure"
method?: string
locked?: boolean
client?: string
ip?: string
country?: string
region?: string
city?: string
browser?: string
os?: string
model?: string
}[]
cursor: null | string
}/ v1/ orgs/ :orgId/ tenant/ policies/ assistantCaity in this org (docs/specs/onboarding/caity.md): on or off, the highest mode, the apps she may use; and the choices.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/policies/assistant' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
policy: {
enabled: boolean
maxMode: "ask" | "reads" | "app" | "auto"
apps: null | ("cloud" | "git" | "maps" | "drive" | "photos" | "tenant" | "crm" | "health" | "weather" | "marketing" | "food" | "documents" | "sheets" | "slides" | "video" | "vehicles" | "mirage" | "brain" | "tasks" | "connectors" | "agents")[]
publicShares?: boolean
}
set: boolean
apps: {
id: "cloud" | "git" | "maps" | "drive" | "photos" | "tenant" | "crm" | "health" | "weather" | "marketing" | "food" | "documents" | "sheets" | "slides" | "video" | "vehicles" | "mirage" | "brain" | "tasks" | "connectors" | "agents"
label: string
detail: string
}[]
modes: ("ask" | "reads" | "app" | "auto")[]
}/ v1/ orgs/ :orgId/ tenant/ policies/ assistantSets Caity's policy: { enabled, maxMode, apps, publicShares } (apps: null: every app). Narrowing by owners and admins, widening by owners; audited.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
enabledbooleanrequiredmaxMode"ask" | "reads" | "app" | "auto"requiredappsstring[]requiredor nullUp to 40 items. Each up to 32 characters.
publicSharesboolean
Errors
400Choose apps Caity has in organisations.404Organization not found
curl -X PUT 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/policies/assistant' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"maxMode": "ask",
"apps": [
"example"
]
}'Response 200
{
policy: {
enabled: boolean
maxMode: "ask" | "reads" | "app" | "auto"
apps: null | ("cloud" | "git" | "maps" | "drive" | "photos" | "tenant" | "crm" | "health" | "weather" | "marketing" | "food" | "documents" | "sheets" | "slides" | "video" | "vehicles" | "mirage" | "brain" | "tasks" | "connectors" | "agents")[]
publicShares?: boolean
}
set: boolean
apps: {
id: "cloud" | "git" | "maps" | "drive" | "photos" | "tenant" | "crm" | "health" | "weather" | "marketing" | "food" | "documents" | "sheets" | "slides" | "video" | "vehicles" | "mirage" | "brain" | "tasks" | "connectors" | "agents"
label: string
detail: string
}[]
modes: ("ask" | "reads" | "app" | "auto")[]
}/ v1/ orgs/ :orgId/ tenant/ policiesThe sign-in policy and the members it would leave without access.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
Errors
404Organization not found
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/policies' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
signIn: {
strength: "any" | "mfa" | "passkey"
methods: ("passkey" | "apple" | "google" | "password")[]
graceUntil?: number
sessionHours?: number
}
coverage: {
members: number
affected: {
userId: string
email?: string
name?: string
passkeys: number
textCode: boolean
authenticator: boolean
}[]
}
}/ v1/ orgs/ :orgId/ tenant/ policies/ sign-inSets the sign-in policy (owners): required strength (any, mfa: a passkey or text codes, passkey), allowed methods, a grace period in days and the longest a sign-in lasts in hours.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
strength"any" | "mfa" | "passkey"requiredmethods("password" | "passkey" | "apple" | "google")[]required1–4 items.
graceDaysintegerDefault
0. 0–90.sessionHoursintegeror null1–720.
Errors
400Allow at least one sign-in method.400Requiring a passkey needs passkeys allowed.400A grace period is 0 to 90 days.400Sign-ins can last 1 hour to 30 days.404Organization not found409You don't meet this policy yet. Add a passkey first, or give a grace period.
curl -X PUT 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/policies/sign-in' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"strength": "any",
"methods": [
"password"
]
}'Response 200
{
signIn: {
strength: "any" | "mfa" | "passkey"
methods: ("passkey" | "apple" | "google" | "password")[]
graceUntil?: number
sessionHours?: number
}
coverage: {
members: number
affected: {
userId: string
email?: string
name?: string
passkeys: number
textCode: boolean
authenticator: boolean
}[]
}
}/ v1/ orgs/ :orgId/ tenant/ keysEvery key of the organization with its creator, scopes, expiry, status and last use (when, address, country, client). Never secrets.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/keys' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
keys: {
keyId: string
name: string
kind: string
scopes: string[]
git: boolean
machine?: string
createdBy: null | {
userId: string
name?: string
email?: string
}
createdAt?: number
expiresAt?: number
lastUsedAt?: number
lastUsedIp?: string
lastUsedCountry?: string
lastUsedAgent?: string
status: "active" | "expired" | "creator_stopped"
}[]
}/ v1/ orgs/ :orgId/ tenant/ keys/ :keyIdRevokes a key of the organization at once; audited as key.revoke.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).keyIdKey id (
key_…).
Errors
404Key not found
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/keys/{keyId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenant/ usersMembers with sign-in health; pending invites and removed members (restorable for 30 days).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
Query parameters
qstringUp to 200 characters.
role"owner" | "admin" | "developer" | "viewer"status"active" | "blocked" | "guest" | "member"signIn"never" | "30d" | "90d"mfa"yes" | "no"
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
users: {
userId: string
email?: string
name?: string
role: "owner" | "admin" | "developer" | "viewer"
effectiveRole: "owner" | "admin" | "developer" | "viewer"
title?: string
department?: string
status: "active" | "blocked"
blockedAt?: number
guest: boolean
guestExpiresAt?: number
joinedAt?: number
lastSignInAt?: number
lastSignInMethod?: string
passkeys: number
textCode: boolean
authenticator: boolean
mfa: boolean
groups: {
teamId: string
name: string
role: "owner" | "member"
}[]
customRoleIds: string[]
tokensValidAfter?: number
disabledAccount: boolean
}[]
total: number
invites: {
teamIds: string[]
department?: string
title?: string
guestDays?: number
inviteId: string
email: string
role: "owner" | "admin" | "developer" | "viewer"
expiresAt: number
createdAt?: number
invitedBy: string
guest: boolean
}[]
removed: {
userId: string
email?: string
name?: string
role: string
removedAt: number
removedBy: string
restoreUntil: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ users/ exportEvery member as CSV (email, name, role, attributes, status, groups, sign-in health).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/export' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200 with no body
/ v1/ orgs/ :orgId/ tenant/ users/ :userId/ permissionsWhat a member may do here, app by app, and why (their role, groups, custom roles, the plan and app access).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Errors
404That person isn't an active member here.
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/{userId}/permissions' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
space: {
kind: "org" | "personal"
id: string
}
role?: "owner" | "admin" | "developer" | "viewer"
held?: "blocked" | "guest_expired" | "mfa_required" | "passkey_required" | "method_not_allowed" | "reauthenticate" | "session_too_old"
apps: {
app: "org" | "admin" | "calendar" | "cloud" | "git" | "chat" | "knowledge" | "mail" | "issues" | "maps" | "drive" | "photos" | "messaging" | "tenant" | "crm" | "health" | "weather" | "marketing" | "food" | "documents" | "sheets" | "slides" | "contacts" | "studio" | "video" | "vehicles" | "sharing"
label: string
reachable: boolean
reason?: "held" | "not_in_space" | "not_in_plan" | "access_ended" | "app_off" | "not_in_groups" | "no_access"
level: "none" | "edit" | "view" | "manage"
levelLabel: string
words: string
from?: string
}[]
scopes: ("platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write")[]
hidden?: string[]
}/ v1/ orgs/ :orgId/ tenant/ check-accessCheck access: whether a member (user) or anyone in a group (group) may use an app (app) or holds a scope (scope) here, with every layer that decides it (membership, space, plan, app access, role, custom roles). Reads only.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/check-access' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
subject: {
kind: "user" | "group"
id: string
name: string
}
target: {
kind: "app"
app: "org" | "admin" | "calendar" | "cloud" | "git" | "chat" | "knowledge" | "mail" | "issues" | "maps" | "drive" | "photos" | "messaging" | "tenant" | "crm" | "health" | "weather" | "marketing" | "food" | "documents" | "sheets" | "slides" | "contacts" | "studio" | "video" | "vehicles" | "sharing"
label: string
} | {
kind: "scope"
scope: "platform:admin" | "platform:infra" | "platform:analytics" | "platform:coverage" | "org:read" | "org:write" | "audit:read" | "tenant:read" | "tenant:write" | "members:read" | "members:write" | "projects:read" | "projects:write" | "deployments:read" | "deployments:write" | "env:read" | "env:write" | "keys:read" | "keys:use" | "keys:write" | "domains:read" | "domains:write" | "resources:read" | "resources:write" | "git:read" | "git:write" | "git:admin" | "logs:read" | "analytics:read" | "knowledge:read" | "knowledge:write" | "connectors:read" | "connectors:write" | "chat:use" | "mcp:connect" | "agents:read" | "agents:write" | "agents:run" | "mail:read" | "mail:send" | "mail:admin" | "calendar:read" | "calendar:write" | "contacts:read" | "contacts:write" | "issues:read" | "issues:write" | "issues:admin" | "maps:read" | "maps:write" | "drive:read" | "drive:write" | "crm:read" | "crm:write" | "crm:admin" | "marketing:read" | "marketing:write" | "marketing:send" | "marketing:admin" | "health:read" | "health:write" | "weather:read" | "weather:write" | "food:read" | "food:write" | "vehicles:read" | "vehicles:write" | "vehicles:control" | "vehicles:admin" | "sharing:read" | "sharing:write"
app: "org" | "admin" | "calendar" | "cloud" | "git" | "chat" | "knowledge" | "mail" | "issues" | "maps" | "drive" | "photos" | "messaging" | "tenant" | "crm" | "health" | "weather" | "marketing" | "food" | "documents" | "sheets" | "slides" | "contacts" | "studio" | "video" | "vehicles" | "sharing"
label: string
}
allowed: boolean
level: "none" | "edit" | "view" | "manage"
levelLabel: string
answer: string
why: string
steps: {
layer: "role" | "member" | "plan" | "space" | "appAccess" | "customRoles"
title: string
outcome: "fail" | "skip" | "pass"
text: string
}[]
}/ v1/ orgs/ :orgId/ tenant/ users/ :userIdOne member: groups, browser sessions, keys they created, app assignments and recent sign-ins.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Errors
404Not a member of this organization
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/{userId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
user: {
userId: string
email?: string
name?: string
role: "owner" | "admin" | "developer" | "viewer"
effectiveRole: "owner" | "admin" | "developer" | "viewer"
title?: string
department?: string
status: "active" | "blocked"
blockedAt?: number
guest: boolean
guestExpiresAt?: number
joinedAt?: number
lastSignInAt?: number
lastSignInMethod?: string
passkeys: number
textCode: boolean
authenticator: boolean
mfa: boolean
groups: {
teamId: string
name: string
role: "owner" | "member"
}[]
customRoleIds: string[]
tokensValidAfter?: number
disabledAccount: boolean
}
sessions: {
sessionId: string
method?: string
browser?: string
os?: string
deviceKind?: string
ip?: string
country?: string
region?: string
city?: string
createdAt?: number
lastSeenAt?: number
reachesOrg: boolean
}[]
keys: {
keyId: string
name: string
kind: "api" | "mcp" | "agent"
scopes: string[]
lastUsedAt?: number
expiresAt?: number
createdAt?: number
machine: boolean
}[]
apps: string[]
signIns: {
eventId: string
orgId: string
action: string
actor: {
type: "user" | "key" | "device" | "system"
id: string
label?: string
}
target: {
type: string
id: string
label?: string
}
metadata?: {
[key: string]: unknown
}
ip?: string
userAgent?: string
createdAt: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ users/ :userIdRole, title, department, and a guest's access end (epoch seconds, or null).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Request body
role"owner" | "admin" | "developer" | "viewer"titleany JSONor nulldepartmentany JSONor nullguestExpiresAtintegeror null> 0.
Errors
400Guests can be developers or viewers.400Only guests have an access end date.404Organization not found404Not a member of this organization409An organization needs at least one other active owner first.
curl -X PATCH 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/{userId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"role": "owner",
"title": {},
"department": {}
}'Response 200
{
user: {
userId: string
email?: string
name?: string
role: "owner" | "admin" | "developer" | "viewer"
effectiveRole: "owner" | "admin" | "developer" | "viewer"
title?: string
department?: string
status: "active" | "blocked"
blockedAt?: number
guest: boolean
guestExpiresAt?: number
joinedAt?: number
lastSignInAt?: number
lastSignInMethod?: string
passkeys: number
textCode: boolean
authenticator: boolean
mfa: boolean
groups: {
teamId: string
name: string
role: "owner" | "member"
}[]
customRoleIds: string[]
tokensValidAfter?: number
disabledAccount: boolean
}
sessions: {
sessionId: string
method?: string
browser?: string
os?: string
deviceKind?: string
ip?: string
country?: string
region?: string
city?: string
createdAt?: number
lastSeenAt?: number
reachesOrg: boolean
}[]
keys: {
keyId: string
name: string
kind: "api" | "mcp" | "agent"
scopes: string[]
lastUsedAt?: number
expiresAt?: number
createdAt?: number
machine: boolean
}[]
apps: string[]
signIns: {
eventId: string
orgId: string
action: string
actor: {
type: "user" | "key" | "device" | "system"
id: string
label?: string
}
target: {
type: string
id: string
label?: string
}
metadata?: {
[key: string]: unknown
}
ip?: string
userAgent?: string
createdAt: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ users/ :userId/ blockBlocks sign-in to this org: no new tokens; current ones stop at the API and MCP within 30 seconds.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Request body
reasonstringUp to 200 characters. Trimmed.
Errors
400You can't do that to yourself.404Not a member of this organization409An organization needs at least one other active owner first.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/{userId}/block' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"reason": "example"
}'Response 200
{
user: {
userId: string
email?: string
name?: string
role: "owner" | "admin" | "developer" | "viewer"
effectiveRole: "owner" | "admin" | "developer" | "viewer"
title?: string
department?: string
status: "active" | "blocked"
blockedAt?: number
guest: boolean
guestExpiresAt?: number
joinedAt?: number
lastSignInAt?: number
lastSignInMethod?: string
passkeys: number
textCode: boolean
authenticator: boolean
mfa: boolean
groups: {
teamId: string
name: string
role: "owner" | "member"
}[]
customRoleIds: string[]
tokensValidAfter?: number
disabledAccount: boolean
}
sessions: {
sessionId: string
method?: string
browser?: string
os?: string
deviceKind?: string
ip?: string
country?: string
region?: string
city?: string
createdAt?: number
lastSeenAt?: number
reachesOrg: boolean
}[]
keys: {
keyId: string
name: string
kind: "api" | "mcp" | "agent"
scopes: string[]
lastUsedAt?: number
expiresAt?: number
createdAt?: number
machine: boolean
}[]
apps: string[]
signIns: {
eventId: string
orgId: string
action: string
actor: {
type: "user" | "key" | "device" | "system"
id: string
label?: string
}
target: {
type: string
id: string
label?: string
}
metadata?: {
[key: string]: unknown
}
ip?: string
userAgent?: string
createdAt: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ users/ :userId/ unblockUnblocks sign-in; the person signs in again to reach the org.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Errors
400You can't do that to yourself.404Not a member of this organization
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/{userId}/unblock' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
user: {
userId: string
email?: string
name?: string
role: "owner" | "admin" | "developer" | "viewer"
effectiveRole: "owner" | "admin" | "developer" | "viewer"
title?: string
department?: string
status: "active" | "blocked"
blockedAt?: number
guest: boolean
guestExpiresAt?: number
joinedAt?: number
lastSignInAt?: number
lastSignInMethod?: string
passkeys: number
textCode: boolean
authenticator: boolean
mfa: boolean
groups: {
teamId: string
name: string
role: "owner" | "member"
}[]
customRoleIds: string[]
tokensValidAfter?: number
disabledAccount: boolean
}
sessions: {
sessionId: string
method?: string
browser?: string
os?: string
deviceKind?: string
ip?: string
country?: string
region?: string
city?: string
createdAt?: number
lastSeenAt?: number
reachesOrg: boolean
}[]
keys: {
keyId: string
name: string
kind: "api" | "mcp" | "agent"
scopes: string[]
lastUsedAt?: number
expiresAt?: number
createdAt?: number
machine: boolean
}[]
apps: string[]
signIns: {
eventId: string
orgId: string
action: string
actor: {
type: "user" | "key" | "device" | "system"
id: string
label?: string
}
target: {
type: string
id: string
label?: string
}
metadata?: {
[key: string]: unknown
}
ip?: string
userAgent?: string
createdAt: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ users/ :userId/ revoke-sessionsEnds the person's sessions for this org (they sign in again) and disconnects their MCP clients here; keys also revokes keys they created here.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Request body
keysbooleanDefault
false.
Errors
400You can't do that to yourself.404Not a member of this organization
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/{userId}/revoke-sessions' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"keys": false
}'Response 200
{
revoked: {
clients: number
keys: number
}
}/ v1/ orgs/ :orgId/ tenant/ users/ :userIdRemoves the member; restorable with their role, attributes, groups and app assignments for 30 days.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Errors
400You can't do that to yourself.404Not a member of this organization409An organization needs at least one other active owner first.
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/users/{userId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenant/ removed/ :userId/ restoreRestores a removed member.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Errors
404Nothing to restore404Organization not found404The account no longer exists.404Not a member of this organization409They're a member again already.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/removed/{userId}/restore' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
user: {
userId: string
email?: string
name?: string
role: "owner" | "admin" | "developer" | "viewer"
effectiveRole: "owner" | "admin" | "developer" | "viewer"
title?: string
department?: string
status: "active" | "blocked"
blockedAt?: number
guest: boolean
guestExpiresAt?: number
joinedAt?: number
lastSignInAt?: number
lastSignInMethod?: string
passkeys: number
textCode: boolean
authenticator: boolean
mfa: boolean
groups: {
teamId: string
name: string
role: "owner" | "member"
}[]
customRoleIds: string[]
tokensValidAfter?: number
disabledAccount: boolean
}
sessions: {
sessionId: string
method?: string
browser?: string
os?: string
deviceKind?: string
ip?: string
country?: string
region?: string
city?: string
createdAt?: number
lastSeenAt?: number
reachesOrg: boolean
}[]
keys: {
keyId: string
name: string
kind: "api" | "mcp" | "agent"
scopes: string[]
lastUsedAt?: number
expiresAt?: number
createdAt?: number
machine: boolean
}[]
apps: string[]
signIns: {
eventId: string
orgId: string
action: string
actor: {
type: "user" | "key" | "device" | "system"
id: string
label?: string
}
target: {
type: string
id: string
label?: string
}
metadata?: {
[key: string]: unknown
}
ip?: string
userAgent?: string
createdAt: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ removed/ :userIdForgets a removed member now instead of after 30 days.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).userIdA member's user id (
usr_…).
Errors
404Nothing to restore
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/removed/{userId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenant/ invitesInvites one person by email (replacing a pending invite to the same address); the link is mailed and returned.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
emailstringrequiredUp to 254 characters. Email address.
role"owner" | "admin" | "developer" | "viewer"Default
"developer".titleany JSONdepartmentany JSONguestbooleanguestDaysintegerteamIdsstring[]Up to 20 items. Each up to 64 characters.
daysinteger1–30.
Errors
400Unknown role.400Guests can be developers or viewers.400Unknown group.404Organization not found409… is already a member.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/invites' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"email": "person@example.com"
}'Response 201
{
invite: {
inviteId: string
email: string
role: "owner" | "admin" | "developer" | "viewer"
expiresAt: number
link: string
delivered: boolean
}
}/ v1/ orgs/ :orgId/ tenant/ invites/ bulkInvites up to 200 people: csv (email[,role[,title[,department]]], header optional) or rows; defaults apply to each. Rows that fail are reported and the rest are sent.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
csvstringUp to 200,000 characters.
rowsobject[]Up to 200 items.
rows[].emailstringrequiredUp to 254 characters. Email address.
rows[].role"owner" | "admin" | "developer" | "viewer"Default
"developer".rows[].titleany JSONrows[].departmentany JSONrows[].guestbooleanrows[].guestDaysintegerrows[].teamIdsstring[]Up to 20 items. Each up to 64 characters.
rows[].daysinteger1–30.
defaultsobjectdefaults.role"owner" | "admin" | "developer" | "viewer"Default
"developer".defaults.titleany JSONdefaults.departmentany JSONdefaults.guestbooleandefaults.guestDaysintegerdefaults.teamIdsstring[]Up to 20 items. Each up to 64 characters.
defaults.daysinteger1–30.
Also checked: Send csv or rows.
Errors
400Up to 200 invites at once.400Unknown role.400Guests can be developers or viewers.400Unknown group.404Organization not found409… is already a member.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/invites/bulk' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"csv": "example",
"rows": [
{
"email": "person@example.com"
}
],
"defaults": {
"role": "developer",
"title": {},
"department": {}
}
}'Response 200
{
results: {
email: string
ok: true
inviteId: string
delivered: boolean
link: string
} | {
email: string
ok: false
error: string
}[]
errors: {
line: number
message: string
}[]
}/ v1/ orgs/ :orgId/ tenant/ invites/ :inviteId/ resendA new link for a pending invite (the old one stops working), mailed again.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).inviteIdInvite id (
inv_…); undervehicles, Tesla's id for a driver invitation, as the drivers list gives it.
Errors
400Unknown role.400Guests can be developers or viewers.400Unknown group.404Invite not found404Organization not found409… is already a member.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/invites/{inviteId}/resend' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
invite: {
inviteId: string
email: string
role: "owner" | "admin" | "developer" | "viewer"
expiresAt: number
link: string
delivered: boolean
}
}/ v1/ orgs/ :orgId/ tenant/ invites/ :inviteIdRevokes a pending invite (the link stops working).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).inviteIdInvite id (
inv_…); undervehicles, Tesla's id for a driver invitation, as the drivers list gives it.
Errors
404Invite not found
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/invites/{inviteId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenant/ join-codesJoin codes that still work (Invite by Link): role, uses, expiry and who made each; never the codes themselves.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/join-codes' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
codes: {
codeId: string
hint: string
role: string
uses: number
maxUses?: number
expiresAt: number
createdBy: string
createdByName?: string
createdAt?: number
}[]
}/ v1/ orgs/ :orgId/ tenant/ join-codesA join code: anyone signed in who has it joins as role (viewer or developer) for days (1, 7 or 30), up to maxUses people (absent or null: anyone with it). The code and its link are in this answer only.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
role"viewer" | "developer"Default
"viewer".daysintegermaxUsesintegeror null1–500.
curl -X POST 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/join-codes' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"role": "viewer",
"days": 1,
"maxUses": 1
}'Response 201
{
code: {
maxUses?: number
codeId: string
code: string
link: string
role: "developer" | "viewer"
expiresAt: number
}
}/ v1/ orgs/ :orgId/ tenant/ join-codes/ :codeIdStops a join code at once; the people it joined stay.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).codeIdA join code's id (
jcd_…), as Tenant's list of codes gives it.
curl -X DELETE 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/join-codes/{codeId}' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 204 with no body
/ v1/ orgs/ :orgId/ tenantProperties, counts, the sign-in policy and recommendations computed from the org's data.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
Errors
404Organization not found
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
org: {
plan?: {
planId: string
name: string
}
createdAt?: number
nextSlugChangeAt?: number
deploymentSlug?: string
formerSlugs?: string[]
contactEmail?: string
logoUri?: string
orgId: string
slug: string
name: string
kind: "platform" | "customer"
}
counts: {
members: number
active: number
guests: number
blocked: number
admins: number
mfa: number
passkeys: number
groups: number
customRoles: number
apps: number
mcpClients: number
keys: number
invites: number
removed: number
}
policy: {
strength: "any" | "mfa" | "passkey"
methods: ("passkey" | "apple" | "google" | "password")[]
graceUntil?: number
sessionHours?: number
}
recommendations: {
id: string
severity: "low" | "medium" | "high"
title: string
detail: string
count?: number
href: string
}[]
}/ v1/ orgs/ :orgId/ tenantName, logo (https) and contact address.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
namestring1–64 characters. Trimmed.
logoUristring | ""or nullUp to 512 characters. Trimmed.
contactEmailstring | ""or nullUp to 254 characters. Email address.
Errors
404Organization not found
curl -X PATCH 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Example",
"logoUri": "https://example.com",
"contactEmail": "person@example.com"
}'Response 200
{
org: {
plan?: {
planId: string
name: string
}
createdAt?: number
nextSlugChangeAt?: number
deploymentSlug?: string
formerSlugs?: string[]
contactEmail?: string
logoUri?: string
orgId: string
slug: string
name: string
kind: "platform" | "customer"
}
counts: {
members: number
active: number
guests: number
blocked: number
admins: number
mfa: number
passkeys: number
groups: number
customRoles: number
apps: number
mcpClients: number
keys: number
invites: number
removed: number
}
policy: {
strength: "any" | "mfa" | "passkey"
methods: ("passkey" | "apple" | "google" | "password")[]
graceUntil?: number
sessionHours?: number
}
recommendations: {
id: string
severity: "low" | "medium" | "high"
title: string
detail: string
count?: number
href: string
}[]
}/ v1/ orgs/ :orgId/ tenant/ slugA new slug (owners themselves): the old one keeps redirecting and stays the org's (docs/tenant/slug.md).
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:write
Path parameters
orgIdOrganization id (
org_…).
Request body
slugstringrequiredUp to 64 characters. Trimmed. Lowercased.
Errors
400That's the organisation's slug already.404Organization not found409The platform organisation's slug can't change.409Finish setting up the organisation first.409The organisation keeps its last 5 slugs, which all still lead here. Choose one of them to change back.409That slug is taken.
curl -X PUT 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/slug' \
-H "Authorization: Bearer $CACTIVE_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"slug": "example"
}'Response 200
{
org: {
plan?: {
planId: string
name: string
}
createdAt?: number
nextSlugChangeAt?: number
deploymentSlug?: string
formerSlugs?: string[]
contactEmail?: string
logoUri?: string
orgId: string
slug: string
name: string
kind: "platform" | "customer"
}
counts: {
members: number
active: number
guests: number
blocked: number
admins: number
mfa: number
passkeys: number
groups: number
customRoles: number
apps: number
mcpClients: number
keys: number
invites: number
removed: number
}
policy: {
strength: "any" | "mfa" | "passkey"
methods: ("passkey" | "apple" | "google" | "password")[]
graceUntil?: number
sessionHours?: number
}
recommendations: {
id: string
severity: "low" | "medium" | "high"
title: string
detail: string
count?: number
href: string
}[]
}/ v1/ orgs/ :orgId/ tenant/ grantablesServerless App Services and repositories a group can be given write access to.
- Auth
- A person's token or an API key, as Authorization: Bearer.
- Scope
- tenant:read
Path parameters
orgIdOrganization id (
org_…).
curl 'https://api.cactive.com.au/v1/orgs/{orgId}/tenant/grantables' \
-H "Authorization: Bearer $CACTIVE_TOKEN"Response 200
{
grantables: {
type: "project"
id: string
name: string
} | {
type: "repository"
id: string
name: string
}[]
}