Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: MindCloud Public Roles API
version: 2.0.0
description: REST surface under /v2. Authenticate with a company-scoped API key sent as a bearer token. Each key holds a set of permissions; each operation lists the ones it requires as the apiKey security roles. A request may use a permission only while the user who created the key also holds it.
servers:
- url: https://connect.mindcloud.co
security:
- apiKey: []
tags:
- name: Roles
paths:
/v2/roles:
get:
operationId: v2-list-roles
summary: List roles available to the company, including global platform roles (isGlobal)
description: 'List roles available to the company, including global platform roles (isGlobal). Fetch a single role for its permissions.
Each filterable field is also a query parameter: `status=active` matches it exactly, and bracket operators (eq, ne, gt, gte, lt, lte, contains, starts, ends, in, nin) compare, e.g. `createdOn[gte]=2026-01-01` or `status[in]=failed,cancelled`. contains, starts, and ends apply to text fields only.
Requires the API key permission member:view.'
tags:
- Roles
security:
- apiKey:
- member:view
parameters:
- name: fields
in: query
required: false
schema:
type: string
description: 'Comma-separated fields to return; all of them when left out, and id always. Each item then carries only those keys, whatever its schema requires. Fields: id, name, description, isAdmin, isGlobal, createdOn.'
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/offset'
- name: sort
in: query
required: false
schema:
type: string
description: 'Comma-separated sort fields; prefix one with - for descending. Sortable fields: id, name, description, isAdmin, isGlobal, createdOn. Default: name.'
- name: where
in: query
required: false
schema:
type: string
maxLength: 2048
description: 'RSQL filter expression. Filterable fields: id, name, description, isAdmin, isGlobal, createdOn. Operators: ==, !=, >, >=, <, <=, =in=, =out=, =like=. Logical: ; (AND), , (OR); AND binds tighter than OR. Example: "status==active;name=like=Sales*"'
- name: id
in: query
required: false
schema:
type: string
description: 'Filter on id: `id=value` matches it exactly. Bracket operators: `id[ne]`, `id[gt]`, `id[gte]`, `id[lt]`, `id[lte]`, `id[contains]`, `id[starts]`, `id[ends]`, and `id[in]` / `id[nin]` with comma-separated values.'
- name: name
in: query
required: false
schema:
type: string
description: 'Filter on name: `name=value` matches it exactly. Bracket operators: `name[ne]`, `name[gt]`, `name[gte]`, `name[lt]`, `name[lte]`, `name[contains]`, `name[starts]`, `name[ends]`, and `name[in]` / `name[nin]` with comma-separated values.'
- name: description
in: query
required: false
schema:
type: string
description: 'Filter on description: `description=value` matches it exactly. Bracket operators: `description[ne]`, `description[gt]`, `description[gte]`, `description[lt]`, `description[lte]`, `description[contains]`, `description[starts]`, `description[ends]`, and `description[in]` / `description[nin]` with comma-separated values.'
- name: isAdmin
in: query
required: false
schema:
type: boolean
description: 'Filter on isAdmin: `isAdmin=value` matches it exactly. Bracket operators: `isAdmin[ne]`, `isAdmin[gt]`, `isAdmin[gte]`, `isAdmin[lt]`, `isAdmin[lte]`, and `isAdmin[in]` / `isAdmin[nin]` with comma-separated values.'
- name: isGlobal
in: query
required: false
schema:
type: boolean
description: 'Filter on isGlobal: `isGlobal=value` matches it exactly. Bracket operators: `isGlobal[ne]`, `isGlobal[gt]`, `isGlobal[gte]`, `isGlobal[lt]`, `isGlobal[lte]`, and `isGlobal[in]` / `isGlobal[nin]` with comma-separated values.'
- name: createdOn
in: query
required: false
schema:
type: string
description: 'Filter on createdOn: `createdOn=value` matches it exactly. A date or timestamp, such as 2026-10-01 or 2026-10-01T12:00:00Z. Bracket operators: `createdOn[ne]`, `createdOn[gt]`, `createdOn[gte]`, `createdOn[lt]`, `createdOn[lte]`, and `createdOn[in]` / `createdOn[nin]` with comma-separated values.'
- $ref: '#/components/parameters/CompanyId'
responses:
'200':
description: Success.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: true
data:
type: array
items:
$ref: '#/components/schemas/RoleSummary'
meta:
$ref: '#/components/schemas/ListMeta'
required:
- success
- data
- meta
default:
description: Error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
post:
operationId: v2-create-role
summary: Create a role in the company
description: 'Create a role in the company. Names are unique per company, case insensitively. Permissions are given as keys such as "workflow:run".
Requires the API key permission role:manage.'
tags:
- Roles
security:
- apiKey:
- role:manage
parameters:
- $ref: '#/components/parameters/CompanyId'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 255
description:
type: string
maxLength: 255
permissions:
maxItems: 200
type: array
items:
type: string
minLength: 1
maxLength: 255
required:
- name
responses:
'201':
description: Success.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: true
data:
$ref: '#/components/schemas/Role'
meta:
type: object
description: 'Response metadata, on endpoints that answer it: the usage window, a step count, or the provider paging of a Universal action run.'
required:
- success
- data
'400':
description: The request body is invalid (INVALID_QUERY, ROLE_CREATE_INVALID_REQUEST), names permission keys that do not exist (ROLE_PERMISSIONS_UNKNOWN_KEYS), or the write was refused (ROLE_CREATE_FAILED).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: The key has no resolvable acting user (MEMBER_ACTOR_NOT_RESOLVED), the acting user cannot grant admin permissions (ROLE_PERMISSIONS_ADMIN_FORBIDDEN), the permission is Owner-only (ROLE_PERMISSIONS_OWNER_ONLY), the acting user does not hold a permission it adds (ROLE_PERMISSIONS_EXCEED_ACTOR), or a key of the parent organization tried to grant a reserved permission (ROLE_PERMISSIONS_PARENT_DELEGATE_FORBIDDEN).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: A role with this name already exists in the company (ROLE_CREATE_DUPLICATE_NAME).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: The role write failed (ROLE_CREATE_QUERY_FAILED), or the role was written but could not be read back (ROLE_RELOAD_FAILED).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
default:
description: Error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/v2/roles/{roleId}:
get:
operationId: v2-get-role
summary: Get one role with its permissions
description: 'Get one role with its permissions.
Requires the API key permission member:view.'
tags:
- Roles
security:
- apiKey:
- member:view
parameters:
- name: roleId
in: path
required: true
schema:
type: string
minLength: 1
- $ref: '#/components/parameters/CompanyId'
responses:
'200':
description: Success.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: true
data:
$ref: '#/components/schemas/Role'
meta:
type: object
description: 'Response metadata, on endpoints that answer it: the usage window, a step count, or the provider paging of a Universal action run.'
required:
- success
- data
default:
description: Error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
patch:
operationId: v2-update-role
summary: Update a role the company owns
description: 'Update a role the company owns. Global platform roles answer 404 and cannot be changed here. A "permissions" array replaces the role''s whole permission set; leave it out to keep the current set.
Requires the API key permission role:manage.'
tags:
- Roles
security:
- apiKey:
- role:manage
parameters:
- name: roleId
in: path
required: true
schema:
type: string
minLength: 1
- $ref: '#/components/parameters/CompanyId'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 255
description:
type: string
maxLength: 255
permissions:
maxItems: 200
type: array
items:
type: string
minLength: 1
maxLength: 255
responses:
'200':
description: Success.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: true
data:
$ref: '#/components/schemas/Role'
meta:
type: object
description: 'Response metadata, on endpoints that answer it: the usage window, a step count, or the provider paging of a Universal action run.'
required:
- success
- data
'400':
description: The request body is invalid (INVALID_QUERY, ROLE_UPDATE_INVALID_REQUEST), carries none of name, description or permissions (NO_FIELDS_TO_UPDATE), names permission keys that do not exist (ROLE_PERMISSIONS_UNKNOWN_KEYS), or the write was refused (ROLE_UPDATE_FAILED).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: The key has no resolvable acting user (MEMBER_ACTOR_NOT_RESOLVED), the acting user cannot grant admin permissions (ROLE_PERMISSIONS_ADMIN_FORBIDDEN), the permission is Owner-only (ROLE_PERMISSIONS_OWNER_ONLY), the acting user does not hold a permission it adds (ROLE_PERMISSIONS_EXCEED_ACTOR), or a key of the parent organization tried to grant a reserved permission (ROLE_PERMISSIONS_PARENT_DELEGATE_FORBIDDEN).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: No role with this id belongs to the company; global roles answer here too (ROLE_UPDATE_NOT_FOUND).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: Another role in the company already has this name (ROLE_UPDATE_DUPLICATE_NAME).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: The role write failed (ROLE_UPDATE_QUERY_FAILED), or the role was written but could not be read back (ROLE_RELOAD_FAILED).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
default:
description: Error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
delete:
operationId: v2-delete-role
summary: Delete a role the company owns
description: 'Delete a role the company owns. A role that still has members answers 400; move those members to another role first. Global platform roles answer 404 because they are not the company''s to delete.
Requires the API key permission role:manage.'
tags:
- Roles
security:
- apiKey:
- role:manage
parameters:
- name: roleId
in: path
required: true
schema:
type: string
minLength: 1
- $ref: '#/components/parameters/CompanyId'
responses:
'200':
description: Success.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: true
data:
$ref: '#/components/schemas/DeletedResource'
meta:
type: object
description: 'Response metadata, on endpoints that answer it: the usage window, a step count, or the provider paging of a Universal action run.'
required:
- success
- data
'400':
description: The request is invalid (INVALID_QUERY, ROLE_DELETE_INVALID_REQUEST), the role still has members (ROLE_DELETE_ASSIGNED_USERS_FORBIDDEN), or the delete was refused (ROLE_DELETE_FAILED).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: The key has no resolvable acting user (MEMBER_ACTOR_NOT_RESOLVED).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: No role with this id belongs to the company; global roles answer here too (ROLE_DELETE_NOT_FOUND).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: The delete query failed (ROLE_DELETE_QUERY_FAILED).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
default:
description: Error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
Role:
type: object
properties:
id:
type:
- string
- 'null'
description: Unique id of the role.
name:
type:
- string
- 'null'
description: The role's name.
description:
type:
- string
- 'null'
description: The role's description. Empty when nobody wrote one.
isAdmin:
type:
- boolean
- 'null'
description: True if the role grants admin rights.
isGlobal:
type:
- boolean
- 'null'
description: 'True for roles MindCloud provides to every company. Global roles are read-only: writing one answers 404.'
createdOn:
type:
- string
- 'null'
format: date-time
description: When the role was created.
permissions:
type:
- array
- 'null'
items:
type: object
properties:
key:
type:
- string
- 'null'
description: The permission key, such as workflow:run.
name:
type:
- string
- 'null'
description: The permission's display name.
description: Everything the role allows, as { key, name } pairs.
required:
- id
- name
- description
- isAdmin
- isGlobal
- createdOn
- permissions
RoleSummary:
type: object
properties:
id:
type:
- string
- 'null'
description: Unique id of the role.
name:
type:
- string
- 'null'
description: The role's name.
description:
type:
- string
- 'null'
description: The role's description. Empty when nobody wrote one.
isAdmin:
type:
- boolean
- 'null'
description: True if the role grants admin rights.
isGlobal:
type:
- boolean
- 'null'
description: 'True for roles MindCloud provides to every company. Global roles are read-only: writing one answers 404.'
createdOn:
type:
- string
- 'null'
format: date-time
description: When the role was created.
required:
- id
- name
- description
- isAdmin
- isGlobal
- createdOn
ErrorResponse:
type: object
properties:
success:
type: boolean
const: false
error:
type: object
properties:
code:
type: string
description: 'Fixed by the status: 400 VALIDATION_FAILED, 401 UNAUTHORIZED, 403 FORBIDDEN, 404 NOT_FOUND, 409 CONFLICT, 410 GONE, 413 PAYLOAD_TOO_LARGE, 421 and 503 UNAVAILABLE, 429 RATE_LIMITED, 500 INTERNAL_ERROR, 502 PROVIDER_ERROR.'
examples:
- VALIDATION_FAILED
- UNAUTHORIZED
- FORBIDDEN
- NOT_FOUND
- CONFLICT
- GONE
- PAYLOAD_TOO_LARGE
- RATE_LIMITED
- INTERNAL_ERROR
- PROVIDER_ERROR
- UNAVAILABLE
message:
type: string
details:
type: object
description: The specific cause (reason) and any evidence for it. Absent when the code says everything.
properties:
reason:
type: string
description: The specific cause, for example UNKNOWN_FILTER_FIELD or CONNECTION_IN_USE.
field:
type: string
description: The parameter, filter, sort, or body field a 400 refused.
accepted:
type: array
items: {}
description: 'What a 400 would have accepted instead: parameter names, field names, or enum values.'
provider:
type: object
description: 'On 502 PROVIDER_ERROR: the provider answer that failed.'
properties:
status:
type: integer
description: The provider's HTTP status.
code:
type: string
description: The provider's own error code, when it sends one.
required:
- code
- message
required:
- success
- error
ListMeta:
type: object
properties:
pagination:
type: object
properties:
totalCount:
type: integer
description: Matching records. A list read in SQL stops counting at 10000.
totalCountExact:
type: boolean
description: False when totalCount stopped at that cap.
hasNextPage:
type: boolean
description: True when another page follows. Page with this, not totalCount.
hasPreviousPage:
type: boolean
required:
- totalCount
- totalCountExact
- hasNextPage
- hasPreviousPage
required:
- pagination
DeletedResource:
type: object
properties:
id:
type: string
description: The id of the resource that was deleted.
required:
- id
parameters:
offset:
name: offset
in: query
required: false
schema:
type: integer
minimum: 0
default: 0
description: Number of results to skip for pagination (default 0).
limit:
name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 1000
default: 100
description: Maximum number of results to return (1-1000, default 100).
CompanyId:
name: X-Company-Id
in: header
required: false
schema:
type: string
example: K3vX9qLm2RtA
description: Optional. The id of a child organization of your API key's company to act on. Leave it out to act on the key's own company. See [Child organizations](https://mindcloud.co/docs/api/rest/introduction/child-organizations).
securitySchemes:
apiKey:
type: http
scheme: bearer
description: 'Company-scoped MindCloud API key sent as `Authorization: Bearer <key>`. Each key holds permissions from the MindCloud roles catalog (workflow:view, workflow:run, universal:read, api_key:manage, ...), chosen when it is created; each operation lists the ones it requires as this scheme''s roles. A request may use a permission only while the user who created the key still holds it in the company the request acts on; a missing one answers 403 with details.reason API_KEY_PERMISSION_DENIED and details.required, and a key whose creator left the organization answers API_KEY_CREATOR_INACTIVE. The key''s accessLevel (full_access, run_workflows, read_only, or none) summarizes its permissions. Create a key at https://app.mindcloud.co/user/api-keys.'