Workflow Nodes
Browse, create, and manage workflow node types. Node types define the building blocks available in the workflow builder, including data sources, transformations, AI models, and custom logic. System nodes are read-only and cannot be modified or deleted.
All endpoints require authentication via X-API-Key header and the appropriate scope.
WorkflowNode Object
{
"_id": "node_type_001",
"nodeId": "mysql-sources",
"type": "mysql",
"category": "sources",
"name": "MySQL",
"label": "MySQL",
"description": "Query data from MySQL database",
"mcpDescription": "Executes SQL queries against MySQL database to fetch data. ...",
"version": "1.1.3",
"author": "Strongly AI",
"tags": ["source", "mysql", "database", "sql", "query"],
"icon": "Database",
"color": "#10b981",
"isSystem": true,
"isActive": true,
"allowMultipleInputs": false,
"allowedInputs": [
{ "name": "params", "type": "array", "required": false, "description": "Query parameters for prepared statements" }
],
"allowedOutputs": [
{ "name": "rows", "type": "array", "description": "Query result rows" }
],
"maxInputs": 1,
"maxOutputs": 1,
"editorConfig": {
"title": "Configure MySQL Source",
"description": "Select MySQL connection and configure query",
"fields": []
},
"inputDefinition": "{\"structure\":{...}}",
"outputDefinition": "{\"structure\":{...}}",
"connectors": {
"inputs": [{ "id": "input", "position": "left", "label": "Input" }],
"outputs": [{ "id": "output", "position": "right", "label": "Output" }]
},
"resources": { "timeout": 0, "memory": "1Gi", "cpu": "300m" },
"metadata": {},
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-15T00:00:00Z"
}
_id is the node type's ID in these endpoints; nodeId is its catalog identity (what POST /workflows/:id/nodes takes). A custom node also carries owner, organizationId, permissions, functionDefinition, currentVersion, createdBy and updatedBy, and has isSystem: false.
GET /api/v1/workflow-nodes
List available workflow node types.
Scope: workflows:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
active | boolean | No | Filter by active status (default: true) |
category | string | No | Filter by category, e.g. sources, destinations, transforms, ai, logic |
type | string | No | Filter by type, e.g. database, file, api, model |
isSystem | boolean | No | Filter by system vs. custom nodes |
q | string | No | Search by label, name, or description |
limit | integer | No | Number of results to return (default: 50, max: 200) |
cursor | string | No | meta.nextCursor of the previous page; omit for the first page |
sort | string | No | Sort field, prefixed with - for descending (default: -createdAt). Ignored with q, whose results are ranked by relevance |
Response 200 OK
{
"data": [
{
"_id": "node_type_001",
"nodeId": "mysql-sources",
"type": "mysql",
"category": "sources",
"name": "MySQL",
"label": "MySQL",
"description": "Query data from MySQL database",
"version": "1.1.3",
"author": "Strongly AI",
"tags": ["source", "mysql", "database", "sql", "query"],
"icon": "Database",
"isSystem": true,
"isActive": true,
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-15T00:00:00Z"
}
],
"meta": {
"total": 35,
"limit": 50,
"nextCursor": null,
"requestId": "req_abc123"
}
}
POST /api/v1/workflow-nodes
Create a custom workflow node type.
Scope: workflows:write
Request Body
{
"label": "Custom Enrichment",
"category": "transforms",
"type": "custom",
"nodeId": "custom-enrichment",
"description": "Enriches records with additional data from an external API",
"version": "1.0.0",
"configSchema": {
"type": "object",
"properties": {
"apiUrl": {
"type": "string",
"description": "External API endpoint"
},
"apiKey": {
"type": "string",
"description": "API authentication key"
}
},
"required": ["apiUrl"]
},
"defaultConfig": {},
"icon": "sparkles",
"inputs": [
{
"id": "input",
"label": "Data",
"type": "data"
}
],
"outputs": [
{
"id": "output",
"label": "Enriched Data",
"type": "data"
}
],
"tags": ["custom", "enrichment"],
"isActive": true,
"functionDefinition": {
"code": "result = {\"enriched\": items}"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Display label for the node |
category | string | Yes | Node category: sources, destinations, transforms, ai, logic |
type | string | Yes | Node type within the category, e.g. database, file, custom |
functionDefinition | object | Yes | The node's executable definition. functionDefinition.code (required) is the Python the node runs; it is validated before the node is saved |
functionDefinition.pipDependencies | string | No | The Python packages the node needs, in requirements.txt format (one requirement per line). A workflow worker installs them once per pod for each version of the node, so items running in parallel share one install; a change to them goes out as a new version of the node |
nodeId | string | No | Unique identifier slug. Auto-generated from label if not provided |
description | string | No | Description of what the node does |
version | string | No | Semantic version (default: 1.0.0) |
configSchema | object | No | JSON Schema defining the node's configuration options |
defaultConfig | object | No | Default configuration values |
icon | string | No | Icon name for the workflow builder UI |
inputs | array | No | Array of input port definitions |
outputs | array | No | Array of output port definitions |
tags | array | No | Array of tag strings |
isActive | boolean | No | Whether the node is active (default: true) |
Response 201 Created
Returns the created WorkflowNode object: every field sent in the request, plus the fields the platform sets.
{
"data": {
"_id": "node_type_002",
"id": "Xq3kP9mW2aB7cD1eF",
"label": "Custom Enrichment",
"category": "transforms",
"type": "custom",
"nodeId": "custom-enrichment",
"description": "Enriches records with additional data from an external API",
"tags": ["custom", "enrichment"],
"functionDefinition": {
"code": "result = {\"enriched\": items}"
},
"version": "1.0.0",
"author": "Custom",
"color": "#6b7280",
"isSystem": false,
"isActive": true,
"permissions": { "isPublic": false, "allowAllUsers": false, "allowedUsers": [] },
"popularityScore": 0,
"currentVersion": 1,
"resources": { "timeout": 0, "memory": null, "cpu": null, "disk": null, "gpu": 0, "gpuType": null },
"owner": "user_456",
"organizationId": "org_xyz",
"createdBy": "user_456",
"updatedBy": "user_456",
"createdAt": "2025-02-01T10:00:00Z",
"updatedAt": "2025-02-01T10:00:00Z"
},
"meta": {
"requestId": "req_abc123"
}
}
GET /api/v1/workflow-nodes/:id
Get a single workflow node type by ID.
Scope: workflows:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Node type ID |
Response 200 OK
Returns the full WorkflowNode object.
GET /api/v1/workflow-nodes/:id/schema
Get the full configuration schema, input/output definitions, and human-readable documentation for a node type. Looks up the node in the catalog first (by node type string), then falls back to the workflowNodes collection by MongoDB _id or type field.
Scope: workflows:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Node type identifier or MongoDB _id |
Response 200 OK
{
"data": {
"type": "mysql",
"name": "MySQL",
"category": "sources",
"tags": ["source", "mysql", "database", "sql", "query"],
"inputDefinition": {
"type": "object",
"properties": {}
},
"outputDefinition": {
"type": "object",
"properties": {
"rows": { "type": "array" }
}
},
"editorConfig": {},
"connectors": {
"inputs": [],
"outputs": [{ "id": "output" }]
},
"defaultData": {},
"dependencies": [],
"examples": [],
"documentation": "Markdown-formatted documentation for the node."
},
"meta": {
"requestId": "req_abc123"
}
}
PATCH /api/v1/workflow-nodes/:id
Update a custom workflow node type. System nodes cannot be modified.
Scope: workflows:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Node type ID |
Request Body
{
"label": "Custom Enrichment v2",
"description": "Updated enrichment node with batch support",
"version": "2.0.0",
"configSchema": {
"type": "object",
"properties": {
"apiUrl": {
"type": "string",
"description": "External API endpoint"
},
"apiKey": {
"type": "string",
"description": "API authentication key"
},
"batchSize": {
"type": "integer",
"description": "Number of records per batch",
"default": 100
}
},
"required": ["apiUrl"]
},
"defaultConfig": {
"batchSize": 100
},
"tags": ["custom", "enrichment", "batch"]
}
| Field | Type | Required | Description |
|---|---|---|---|
label | string | No | Display label for the node |
description | string | No | Node description |
version | string | No | Semantic version |
configSchema | object | No | JSON Schema for configuration |
defaultConfig | object | No | Default configuration values |
icon | string | No | Icon name |
inputs | array | No | Input port definitions |
outputs | array | No | Output port definitions |
tags | array | No | Tag strings |
isActive | boolean | No | Active status |
Response 200 OK
Returns the updated WorkflowNode object.
Error 403 Forbidden
Returned when attempting to update a system node.
{
"type": "urn:strongly:problem:not-authorized",
"title": "Not allowed",
"status": 403,
"detail": "System nodes cannot be edited via this API",
"code": "not-authorized",
"requestId": "req_abc123"
}
DELETE /api/v1/workflow-nodes/:id
Delete a custom workflow node type. System nodes cannot be deleted.
Scope: workflows:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Node type ID |
Response 204 No Content
Error 403 Forbidden
Returned when attempting to delete a system node.
{
"type": "urn:strongly:problem:not-authorized",
"title": "Not allowed",
"status": 403,
"detail": "System nodes cannot be deleted via this API",
"code": "not-authorized",
"requestId": "req_abc123"
}
POST /api/v1/workflow-nodes/:id/duplicate
Copy a node type (a custom one or a system one) into a new custom node you can edit: the "copy
and edit" flow. The copy is private to you; change it with PATCH /api/v1/workflow-nodes/:id.
Scope: workflows:write
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The node type to copy |
Response 201 Created: the new WorkflowNode object.
Sharing a custom node
A custom node is private to its owner until shared. A member's role is editor (can change it)
or user (can use it in workflows).
| Method | Path | Does | Scope |
|---|---|---|---|
| GET | /api/v1/workflow-nodes/:id/permissions | Owner, members (userId, role) and visibility | workflows:read |
| POST | /api/v1/workflow-nodes/:id/permissions/members | Share with a user: { "userId", "role": "editor" | "user" } | workflows:write |
| DELETE | /api/v1/workflow-nodes/:workflowNodeId/permissions/members/:userId | Stop sharing with a user (204) | workflows:write |
| PATCH | /api/v1/workflow-nodes/:id/permissions | { "visibility": "public" | "private" } | workflows:write |
Each except the removal answers the permissions as they are now: { resourceId, owner, members, visibility }.
GET /api/v1/workflow-nodes/services/data-source-fields/:id
Get the credential field definitions for a data source type (for example, postgres requires host, port, database, username, password). Used by the workflow builder UI to render dynamic connection forms.
Scope: workflows:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Data source type, e.g. mysql, postgres, mongodb, redis, s3, sftp, milvus, elasticsearch |
Response 200 OK
{
"data": {
"type": "postgres",
"name": "PostgreSQL",
"category": "database",
"defaultPort": 5432,
"requiresSSL": false,
"fields": [
{
"name": "host",
"label": "Host",
"type": "string",
"required": true,
"placeholder": "localhost"
},
{
"name": "port",
"label": "Port",
"type": "number",
"required": true,
"placeholder": "5432"
},
{
"name": "database",
"label": "Database",
"type": "string",
"required": true,
"placeholder": null
},
{
"name": "username",
"label": "Username",
"type": "string",
"required": true,
"placeholder": null
},
{
"name": "password",
"label": "Password",
"type": "password",
"required": true,
"placeholder": null
}
]
},
"meta": {
"requestId": "req_abc123"
}
}
GET /api/v1/workflow-nodes/services/data-sources
List data sources available for use in workflow nodes. These are the configured database and file connections that source and destination nodes can connect to.
Scope: workflows:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | No | Filter by data source type, e.g. mysql, postgresql, mongodb, s3 |
category | string | No | Filter by category, e.g. database, file, api |
Response 200 OK
{
"data": {
"count": 2,
"datasources": [
{
"id": "ds_001",
"name": "Production MySQL",
"label": "Production MySQL",
"type": "mysql",
"category": "database",
"status": "connected",
"description": "Primary transactional database"
},
{
"id": "ds_003",
"name": "Data Lake S3",
"label": "Data Lake S3",
"type": "s3",
"category": "file",
"status": "connected",
"description": "Raw landing zone"
}
]
},
"meta": {
"requestId": "req_abc123"
}
}
GET /api/v1/workflow-nodes/services/addons
List add-ons available for use in workflow nodes. Add-ons provide additional capabilities such as caching, message queues, and vector databases.
Scope: workflows:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | No | Filter by add-on type, e.g. redis, rabbitmq, chromadb |
Response 200 OK
{
"data": {
"count": 2,
"addons": [
{
"id": "addon_001",
"label": "Redis Cache",
"type": "redis",
"status": "running",
"version": "8"
},
{
"id": "addon_002",
"label": "Analytics Postgres",
"type": "postgres",
"status": "running",
"version": "18"
}
]
},
"meta": {
"requestId": "req_abc123"
}
}
GET /api/v1/workflow-nodes/services/models
List AI models available for use in workflow nodes. These are the models configured through AI Gateway that can be used in AI-powered nodes.
Scope: workflows:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
provider | string | No | Filter by model provider, e.g. openai, anthropic, google |
type | string | No | Filter by model type, e.g. chat, embedding, image |
Response 200 OK
{
"data": {
"count": 2,
"models": [
{
"id": "model_002",
"name": "Claude Sonnet 4",
"provider": "anthropic",
"vendor": "Anthropic",
"vendorModelId": "claude-sonnet-5-5",
"modelType": "chat",
"status": "active",
"description": "General-purpose chat model",
"capabilities": ["chat", "function-calling"],
"recommended": false
},
{
"id": "model_003",
"name": "Text Embedding 3 Large",
"provider": "openai",
"vendor": "OpenAI",
"vendorModelId": "text-embedding-3-large",
"modelType": "embedding",
"status": "active",
"description": "Embedding model for retrieval",
"capabilities": [],
"recommended": false
}
]
},
"meta": {
"requestId": "req_abc123"
}
}
GET /api/v1/workflow-nodes/suggest-mappings
Suggest input mappings between two node types based on their output and input definitions. Matches by exact field name first, then falls back to common data / input aliases.
Scope: workflows:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Source node type |
targetType | string | Yes | Target node type |
Response 200 OK
{
"data": {
"sourceType": "mysql-source",
"targetType": "ai-gateway",
"suggestedMappings": {
"prompt": "data.prompt",
"data": "data"
},
"sourceOutputFields": ["rows", "rowCount", "prompt"],
"targetInputFields": ["prompt", "model", "data"]
},
"meta": {
"requestId": "req_abc123"
}
}
POST /api/v1/workflow-nodes/sync
Admin-only. Re-scan s3://strongly-shared/workflows/nodes/ and upsert every node definition into the workflowNodes collection. This is the same seeding path the platform runs on startup, and is called by the strongly-ai-workflow-assets CI after a successful publish so the registry catches up without waiting for a platform restart. Idempotent.
Scope: workflows:write (requires an admin API key)
Response 200 OK
{
"data": {
"inserted": 2,
"updated": 15,
"total": 35,
"skipped": [],
"pruned": [],
"source": "s3",
"bucket": "strongly-shared",
"prefix": "workflows/nodes/"
},
"meta": {
"requestId": "req_abc123"
}
}
Error 403 Forbidden
{
"type": "urn:strongly:problem:forbidden",
"title": "Not allowed",
"status": 403,
"detail": "sync-from-s3 requires an admin API key",
"code": "forbidden",
"requestId": "req_abc123"
}