Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: MindCloud Public Embedded 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: embedded
paths:
/v2/embedded/end-users/{endUserId}/connect-links:
post:
operationId: v2-create-embedded-connect-link
summary: Create a single-use hosted link for one end user to connect an available app or…
description: 'Create a single-use hosted link for one end user to connect an available app or repair an owned connection. Requires the embedded:create permission and a configured app integration or Embedded API catalog access.
Requires the API key permission embedded:create.'
tags:
- embedded
security:
- apiKey:
- embedded:create
parameters:
- name: endUserId
in: path
required: true
schema:
type: string
minLength: 1
description: The MindCloud end user ID returned by POST /v1/users.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
appRef:
type: string
minLength: 1
description: The published app slug or ID.
connectionId:
description: The exact public connection ID owned by this end user. SDK accounts update in place. Provisioned accounts without an installation create a new SDK account; reload connections and use its new ID.
type: string
minLength: 1
required:
- appRef
responses:
'201':
description: Success.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: true
data:
$ref: '#/components/schemas/ConnectLink'
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: Invalid request.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Authentication failed.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: API key access, company scope, or app access denied.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: End user, available app, or owned connection not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: API key or end-user connect-link budget exceeded.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'503':
description: Scope, catalog, or connection setup unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
default:
description: Error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/v2/embedded/end-users/{endUserId}/connections:
get:
operationId: v2-list-embedded-end-user-connections
summary: List the non-secret app accounts owned by one end user in the API key company
description: 'List the non-secret app accounts owned by one end user in the API key company. Existing accounts remain visible when Embedded API catalog access is off.
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 embedded:view.'
tags:
- embedded
security:
- apiKey:
- embedded:view
parameters:
- name: endUserId
in: path
required: true
schema:
type: string
- 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, appSlug, appName, label, status, connectedOn.'
- $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, appSlug, appName, label, status, connectedOn. Without sort, results keep the order the list reads them in.'
- name: where
in: query
required: false
schema:
type: string
maxLength: 2048
description: 'RSQL filter expression. Filterable fields: id, appSlug, appName, label, status, connectedOn. 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: appSlug
in: query
required: false
schema:
type: string
description: 'Filter on appSlug: `appSlug=value` matches it exactly. Bracket operators: `appSlug[ne]`, `appSlug[gt]`, `appSlug[gte]`, `appSlug[lt]`, `appSlug[lte]`, `appSlug[contains]`, `appSlug[starts]`, `appSlug[ends]`, and `appSlug[in]` / `appSlug[nin]` with comma-separated values.'
- name: appName
in: query
required: false
schema:
type: string
description: 'Filter on appName: `appName=value` matches it exactly. Bracket operators: `appName[ne]`, `appName[gt]`, `appName[gte]`, `appName[lt]`, `appName[lte]`, `appName[contains]`, `appName[starts]`, `appName[ends]`, and `appName[in]` / `appName[nin]` with comma-separated values.'
- name: label
in: query
required: false
schema:
type: string
description: 'Filter on label: `label=value` matches it exactly. Bracket operators: `label[ne]`, `label[gt]`, `label[gte]`, `label[lt]`, `label[lte]`, `label[contains]`, `label[starts]`, `label[ends]`, and `label[in]` / `label[nin]` with comma-separated values.'
- name: status
in: query
required: false
schema:
type: string
description: 'Filter on status: `status=value` matches it exactly. Bracket operators: `status[ne]`, `status[gt]`, `status[gte]`, `status[lt]`, `status[lte]`, `status[contains]`, `status[starts]`, `status[ends]`, and `status[in]` / `status[nin]` with comma-separated values.'
- name: connectedOn
in: query
required: false
schema:
type: string
description: 'Filter on connectedOn: `connectedOn=value` matches it exactly. A date or timestamp, such as 2026-10-01 or 2026-10-01T12:00:00Z. Bracket operators: `connectedOn[ne]`, `connectedOn[gt]`, `connectedOn[gte]`, `connectedOn[lt]`, `connectedOn[lte]`, and `connectedOn[in]` / `connectedOn[nin]` with comma-separated values.'
responses:
'200':
description: Success.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: true
data:
type: array
items:
$ref: '#/components/schemas/EmbeddedConnection'
meta:
$ref: '#/components/schemas/ListMeta'
required:
- success
- data
- meta
default:
description: Error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
EmbeddedConnection:
type: object
properties:
id:
type:
- string
- 'null'
description: The public connection ID to pass to runs, lookups, or repair links.
appSlug:
type:
- string
- 'null'
description: The app slug used in Universal API routes.
appName:
type:
- string
- 'null'
description: The app display name.
label:
type:
- string
- 'null'
description: The account label the user can recognize.
status:
type:
- string
- 'null'
description: The current connection status.
connectedOn:
type:
- string
- 'null'
format: date-time
description: When the account connected, or when its credential was created.
required:
- id
- appSlug
- appName
- label
- status
- connectedOn
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
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
ConnectLink:
type: object
properties:
url:
type:
- string
- 'null'
description: Show this URL only to the intended end user. The link lasts fifteen minutes and works once.
appName:
type:
- string
- 'null'
description: The app the user will connect.
expiresOn:
type:
- string
- 'null'
format: date-time
description: When the connection link expires.
singleUse:
type:
- boolean
- 'null'
description: Always true. Request a new link if this one was consumed.
required:
- url
- appName
- expiresOn
- singleUse
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).
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.'