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 `. 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.'