Workflows
Create, list, retrieve, update, and delete AI workflows via the Wireflow API.
Workflows are the core resource in Wireflow. Each workflow contains a graph of AI model nodes connected by edges.
List Workflows
GET /api/v1/workflows
Returns all workflows owned by the authenticated user, ordered by most recently updated.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
isActive |
string |
Filter by active status: "true" or "false" |
mediaId |
string |
Filter by project/media ID |
teamId |
string |
Filter by team ID |
Request
curl https://www.wireflow.ai/api/v1/workflows \
-H "Authorization: Bearer sk-your-api-key"
Response 200 OK
[
{
"id": "cm1abc123",
"name": "Product Image Generator",
"description": "Generates product photos from text descriptions",
"webhookId": "whk_xyz789",
"webhookUrl": null,
"isActive": true,
"isPublished": false,
"executionCount": 42,
"lastExecutedAt": "2025-03-15T10:30:00.000Z",
"tags": ["image", "product"],
"createdAt": "2025-01-10T08:00:00.000Z",
"updatedAt": "2025-03-15T10:30:00.000Z"
}
]
Create a Workflow
POST /api/v1/workflows
Creates a new workflow. The nodes and edges arrays define the workflow graph.
Build nodes from the node catalog (GET /api/v1/nodes). It declares every node's ports, config keys, enum options, defaults, and pricing. The write path lints the graph against it: unknown node types are rejected, unknown config keys and bad enum values come back as warnings in the response meta.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string |
Yes | Workflow name |
description |
string |
No | Workflow description |
nodes |
Node[] |
Yes | Array of workflow nodes |
edges |
Edge[] |
Yes | Array of connections between nodes |
tags |
string[] |
No | Tags for organizing workflows |
isActive |
boolean |
No | Whether the workflow is active (default: true) |
webhookId |
string |
No | Webhook identifier for triggering via HTTP |
mediaId |
string |
No | Project/media ID to scope the workflow to |
Request
curl -X POST https://www.wireflow.ai/api/v1/workflows \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "My Workflow",
"description": "Generates images from prompts",
"nodes": [
{
"id": "node-1",
"type": "basedNode",
"position": { "x": 0, "y": 0 },
"data": {
"label": "Text to Image",
"nodeType": "model:fal:text-to-image",
"category": "model",
"prompt": "A sunset over mountains"
}
}
],
"edges": [],
"tags": ["image"]
}'
Response 201 Created
{
"id": "cm1abc123",
"name": "My Workflow",
"description": "Generates images from prompts",
"nodes": [...],
"edges": [],
"webhookId": null,
"isActive": true,
"tags": ["image"],
"userId": 1,
"createdAt": "2025-03-20T12:00:00.000Z",
"updatedAt": "2025-03-20T12:00:00.000Z"
}
Get a Workflow
GET /api/v1/workflows/{id}
Retrieves a single workflow by ID, including its last 10 executions.
Request
curl https://www.wireflow.ai/api/v1/workflows/cm1abc123 \
-H "Authorization: Bearer sk-your-api-key"
Response 200 OK
{
"id": "cm1abc123",
"name": "My Workflow",
"description": "Generates images from prompts",
"nodes": [...],
"edges": [...],
"webhookId": null,
"isActive": true,
"isPublished": false,
"tags": ["image"],
"createdAt": "2025-03-20T12:00:00.000Z",
"updatedAt": "2025-03-20T12:00:00.000Z",
"executions": [
{
"id": "exec_456",
"status": "COMPLETED",
"triggeredBy": "manual",
"startedAt": "2025-03-20T12:01:00.000Z",
"completedAt": "2025-03-20T12:01:15.000Z",
"executionTime": 15000,
"error": null
}
],
"isOwner": true,
"canEdit": true,
"canDuplicate": true,
"userRole": "OWNER"
}
Update a Workflow
PUT /api/v1/workflows/{id}
Updates an existing workflow. All fields are optional; only include the fields you want to change.
When sending nodes/edges, build them against the node catalog. Responses from GET /api/v1/workflows/{id} round-trip cleanly: canvas runtime fields (width, height, positionAbsolute, selected, dragging) are stripped on read and on write, so you never persist stale view state.
Request Body
| Field | Type | Description |
|---|---|---|
name |
string |
Workflow name |
description |
string | null |
Workflow description |
nodes |
Node[] |
Updated nodes array |
edges |
Edge[] |
Updated edges array |
tags |
string[] |
Tags |
isActive |
boolean |
Active status |
webhookId |
string |
Webhook identifier |
webhookUrl |
string |
Webhook callback URL |
Request
curl -X PUT https://www.wireflow.ai/api/v1/workflows/cm1abc123 \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Workflow Name",
"isActive": false
}'
Response 200 OK
Returns the full updated workflow object.
Delete a Workflow
DELETE /api/v1/workflows/{id}
Soft-deletes a workflow. The workflow is deactivated and marked as deleted but can be recovered by support.
Request
curl -X DELETE https://www.wireflow.ai/api/v1/workflows/cm1abc123 \
-H "Authorization: Bearer sk-your-api-key"
Response 200 OK
{
"success": true
}
Data Types
Node Object
Nodes represent AI models, inputs, and utilities on the workflow canvas. Every node uses the React Flow Node structure.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | Unique node identifier (e.g. "node-1") |
type |
string |
Yes | Always "basedNode" for standard nodes |
position |
object |
Yes | Canvas layout coordinates: { "x": 0, "y": 0 } |
data |
object |
Yes | Node configuration (see below) |
data fields:
| Field | Type | Required | Description |
|---|---|---|---|
label |
string |
Yes | Display name shown on the node |
category |
string |
Yes | Node category: "model", "input", "utility", "output", "logic" |
nodeType |
string |
Yes | Identifies the model or utility (see common values below) |
config |
object |
No | Node settings (prompt, seed, guidance_scale, etc.). This is the canonical bag. |
params |
object |
No | Legacy read location. Avoid — see the warning below. |
inputs |
Port[] |
No | Input port definitions: [{ "id": "image", "label": "Image", "type": "IMAGE" }] |
outputs |
Port[] |
No | Output port definitions: [{ "id": "image", "label": "Image", "type": "IMAGE" }] |
Write settings to
config, notparams. At run time the resolver merges{...config, ...params, ...inputs}, soparamsWINS overconfig— but normalization and rehydration only ever touchconfig. A value written toparamstherefore overrides the normalized one and is never itself normalized, which is how a node ends up running something the canvas does not show.paramsis a legacy read location kept for old graphs.
The position field controls where the node appears on the visual canvas. It has no effect on execution — the API uses it to persist layout when saving workflows.
Layout ships with the edit
position has no effect on execution, but a board is a picture a human opens,
so a graph left as a pile of stacked cards discredits the work that produced it.
Do not guess coordinates: card height is browser state and no caller outside the
tab can get it right.
- Read real geometry.
GET /api/v1/workflows/{id}returns every node with a read-onlydims: { width, height, source }. Branch onsource, never on the numbers:measuredis a real rendered box,declaredis a size the user set by dragging a resize handle,estimatedis our per-type model. layoutPendingis the routine outcome — branch on it first. After a structural editmeta.warningsnormally carries alayoutPending:line, and it means NOTHING WAS MOVED: the graph is exactly as you wrote it. Two independent reasons produce it, and both are common. One, an editor tab may be holding the board — repositioning a board an open tab holds makes the editor's conflict self-heal read a harmless 409 as a foreign edit and wedges that user behind a banner they cannot clear, and the server cannot reliably rule the tab out, so it assumes the worst. Two, server-side arrangement is flag-gated and OFF by default until a durable editor-presence signal exists. Plan for this path.- When arrangement is enabled and the board is provably quiet, a write that
adds, removes or rewires nodes is instead ARRANGED by the write itself —
topological columns, producers left of consumers, group frames fitted to
their members with one uniform gap — and the response echoes the new
positions with its own
meta.warningsline. A write that changes only VALUES (a prompt, a result, a rename) is not a topology change and is never rearranged. PassautoLayout: falseto keep your own coordinates. - Your grouping is never changed, on either path. It is a semantic choice only you can make, and a grouping the wiring disagrees with comes back as an advisory, never a silent regroup.
- Adds are guarded for you either way. A node this PUT ADDS that arrives
with no position, stacked on another, or burying one is repositioned before
it is persisted, and every move is named in the response's
meta.warningswith the node id and its new coordinates. Only nodes the write added are ever moved, because an existing position belongs to the user. - Removals are still yours on the pending path. A delete leaves a hole and a rewire crosses edges, and neither shows up anywhere else in the response body.
- Arrange on demand, any time.
POST /api/v1/workflows/{id}/layoutis the same engine as the in-app Auto Layout button and stays available whether or not the write arranged for you — it is what you call after alayoutPending. It is group-aware, and it refuses any board over 250 nodes or 750 edges with a 422. Pass ascopearray of node ids to lay out just the part you changed. - What "geometry only" actually covers. The layout authors node positions, a
group box's size, and a group box's derived
childNodeIds, and it DELETES the legacy ReactFlowparentId/parentNode/extentkeys from any node it lays out (it applies absolute positions, which ReactFlow would otherwise read as parent-relative; only weavy-imported boards carry them). Yourconfig,prompt,type,resultand the edge list are never touched, so you do not need to re-verify the graph afterwards.
An edit is not done until the board is tidy.
Common nodeType values:
| nodeType | Description |
|---|---|
generate:flux_2 |
Flux 2 text-to-image |
generate:flux_2_pro |
Flux 2 Pro text-to-image |
generate:nano_banana_pro |
Nano Banana Pro image gen |
generate:imagen3 |
Google Imagen 3 |
generate:imagen4 |
Google Imagen 4 |
generate:bytedance_seedream_v4_text_to_image |
Seedream v4 text-to-image |
edit:flux_2_edit |
Flux 2 image editing |
edit:nano_banana_pro_edit |
Nano Banana Pro editing |
edit:bytedance_seedream_v4_edit |
Seedream v4 editing |
video:kling_video_2_5_i2v |
Kling 2.5 image-to-video |
talking:veed_fabric |
VEED Fabric talking head |
input:text |
Text input |
input:image |
Image/media upload |
output:preview |
Preview output |
utility:prompt_concat |
Prompt concatenator |
Edge Object
Edges define connections between node ports.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | Unique edge identifier (e.g. "edge-1") |
source |
string |
Yes | Source node ID |
target |
string |
Yes | Target node ID |
sourceHandle |
string |
No | Output port ID on the source node (e.g. "out-image") |
targetHandle |
string |
No | Input port ID on the target node (e.g. "in-image") |
Validation limits: Max 100 nodes and 500 edges per workflow. Node data nesting is limited to 10 levels deep.
Permissions
Workflow access is determined by:
- Workflow creator — full access
- Media/project owner — full access if the workflow belongs to their project
- Team member — access if the workflow belongs to a team project
- Explicit permission — granted via sharing (EDIT or OWNER)
Delete requires ownership — team members need the OWNER role on the team to delete workflows.