Topolo Docs Topolo Platform
Open workspace

Update a flow

Rename, describe, pause, activate or replace the graph of a selected automation.

Outcome

Rename, describe, pause, activate or replace the graph of a selected automation.

Before you start

  • Verify authenticated identity, environment and the approved organization context before preparing an action.
  • The published application permission is workspace:write. Discover and bind the exact granted Flow workspace. Supplied ids do not grant access.
  • Session callers need read_write or admin workspace access. Auth-introspected API keys must bind that workspace and satisfy workspace:write. The application permission and workspace boundary are separate checks.
  • Authorize the documented mutation effects before CLI --confirm or MCP confirm:true. Fixture credentials and ids authorize no live operation.

Discover the target

topolo whoami --json
topolo actions get app_topolo_flow.flows.update --detail --json
topolo resources topolo-flow --json
topolo workspaces list topolo-flow --json
  • Set FLOW_WORKSPACE_ID to the exact id returned by granted workspace discovery.
  • Discover flowId using flows.list or a retained creation response in this workspace.

Request

PATCH /api/flows/{flowId}

Inspect and test this action. Save the exact input object as payload.json; resource context is supplied separately.

Input fields

FieldRequiredMeaningConstraints
flowIdRequiredExact flow.id returned by creation, flows.list or flows.get in this granted workspace.{"minLength":1}
nameOptionalFlow display name, at most 120 characters; omission during creation selects the default name.{"maxLength":120}
descriptionOptionalFlow description; update accepts null to clear it.{}
statusOptionaldraft, active or paused. Activation enables automatic triggers; an explicitly authorized manual run can execute draft or paused flows.{"enum":["draft","active","paused"]}
graphOptionalNode and edge graph. Each node declares id, type, position and data.kind. Shape and app-action authorization are checked before writes; activation additionally requires a runnable trigger and step.{}

View the full input schema through the action reference or CLI/MCP discovery.

Effects

  • Updates supplied fields only; a supplied graph derives trigger metadata. Activating or editing an active graph requires a runnable trigger and step. Referenced app actions must exist in the caller catalog. Changing schedule configuration recomputes next-run timing; manual execution does not require active status.
  • The schema includes trigger.event, but shape validation refuses it with event_triggers_not_available. Event-based activation is not supported.
  • Session callers need read_write or admin access to the exact granted Flow workspace, in addition to the published application permission. Auth-introspected API keys use their bound workspace and workspace:write; supplying an id never grants access.

Interpret the response

Read $.flow.id for the returned flow identifier. An empty collection does not discover a target.

Read flows.get and compare exact intended fields/graph/trigger metadata; do not infer that a schedule or provider actually ran.

View the complete success schema. Success examples below preserve the actual exported Worker responses; errors have their original refusal shapes. CLI/MCP add their transport envelope, and --detail requests the full CLI response.

Worked examples

Captured from the actual exported Flow Worker with both local SQLite D1 stores and all committed migrations, synthetic Auth identity/grants and simulated Nexus, archive and Workflow-acceptance transports. Fixture credentials and identifiers authorize no live operation. No live provider invocation, credential storage, notification delivery, metering acceptance, durable Workflow execution, deployment, backup erasure or production completion is established by these captures. Refused examples explain boundaries and must not be executed as successful workflows.

Refused request · HTTP 403

Actual exported Worker response with both local SQLite D1 databases and all committed migrations; synthetic Auth/grants and simulated Nexus/archive transport. No live credentials, provider calls, delivery, deployment or durable Workflow execution proof. Scenario: read workspace grant refused.

Input · payload.json:

{
  "flowId": "synthetic_missing",
  "name": "Refused edit"
}

CLI:

topolo actions validate app_topolo_flow.flows.update --data @payload.json --json
topolo actions plan app_topolo_flow.flows.update --resource-type workspace --resource-id "$FLOW_WORKSPACE_ID" --data @payload.json --json

Captured local response · HTTP 403:

{
  "error": "This workspace requires read_write access",
  "code": "workspace_access_insufficient"
}

HTTP 403. The handler refused this request. Resolve the exact cause before retrying; invalid input can be refused by CLI validation before reaching the handler.

Refused request · HTTP 401

Actual exported Worker response with both local SQLite D1 databases and all committed migrations; synthetic Auth/grants and simulated Nexus/archive transport. No live credentials, provider calls, delivery, deployment or durable Workflow execution proof. Scenario: anonymous action.

Input · payload.json:

{
  "flowId": "synthetic_missing"
}

CLI:

topolo actions validate app_topolo_flow.flows.update --data @payload.json --json
topolo actions plan app_topolo_flow.flows.update --resource-type workspace --resource-id "$FLOW_WORKSPACE_ID" --data @payload.json --json

Captured local response · HTTP 401:

{
  "error": "Authentication token required"
}

HTTP 401. The handler refused this request. Resolve the exact cause before retrying; invalid input can be refused by CLI validation before reaching the handler.

Successful request

Actual exported Worker response with both local SQLite D1 databases and all committed migrations; synthetic Auth/grants and simulated Nexus/archive transport. No live credentials, provider calls, delivery, deployment or durable Workflow execution proof. Scenario: declared development webhook host.

Input · payload.json:

{
  "flowId": "flow_f100819994ff480d81a7",
  "graph": {
    "nodes": [
      {
        "id": "trigger",
        "type": "trigger",
        "position": {
          "x": 0,
          "y": 0
        },
        "data": {
          "kind": "trigger.webhook"
        }
      },
      {
        "id": "transform",
        "type": "logic",
        "position": {
          "x": 240,
          "y": 0
        },
        "data": {
          "kind": "core.transform",
          "config": {
            "assignments": {
              "message": "{{trigger.message}}"
            }
          }
        }
      }
    ],
    "edges": [
      {
        "id": "trigger-transform",
        "source": "trigger",
        "target": "transform"
      }
    ]
  }
}

CLI:

topolo actions validate app_topolo_flow.flows.update --data @payload.json --json
topolo actions plan app_topolo_flow.flows.update --resource-type workspace --resource-id "$FLOW_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_flow.flows.update --resource-type workspace --resource-id "$FLOW_WORKSPACE_ID" --data @payload.json --confirm --detail --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_flow.flows.update",
    "input": {
      "flowId": "flow_f100819994ff480d81a7",
      "graph": {
        "nodes": [
          {
            "id": "trigger",
            "type": "trigger",
            "position": {
              "x": 0,
              "y": 0
            },
            "data": {
              "kind": "trigger.webhook"
            }
          },
          {
            "id": "transform",
            "type": "logic",
            "position": {
              "x": 240,
              "y": 0
            },
            "data": {
              "kind": "core.transform",
              "config": {
                "assignments": {
                  "message": "{{trigger.message}}"
                }
              }
            }
          }
        ],
        "edges": [
          {
            "id": "trigger-transform",
            "source": "trigger",
            "target": "transform"
          }
        ]
      }
    },
    "resourceType": "workspace",
    "resourceId": "<id returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "flow": {
    "id": "flow_f100819994ff480d81a7",
    "orgId": "org_flow_fixture",
    "workspaceId": "ws_flow_fixture",
    "name": "Manual fixture",
    "description": null,
    "status": "draft",
    "graph": {
      "nodes": [
        {
          "id": "trigger",
          "type": "trigger",
          "position": {
            "x": 0,
            "y": 0
          },
          "data": {
            "kind": "trigger.webhook"
          }
        },
        {
          "id": "transform",
          "type": "logic",
          "position": {
            "x": 240,
            "y": 0
          },
          "data": {
            "kind": "core.transform",
            "config": {
              "assignments": {
                "message": "{{trigger.message}}"
              }
            }
          }
        }
      ],
      "edges": [
        {
          "id": "trigger-transform",
          "source": "trigger",
          "target": "transform"
        }
      ]
    },
    "triggerType": "webhook",
    "webhookSecret": "whk_daffac264afb4bb49da6",
    "scheduleCron": null,
    "scheduleNextRunAt": null,
    "eventType": null,
    "createdBy": "usr_flow_fixture",
    "createdAt": 1791218517002,
    "updatedAt": 1791218517104,
    "lastRunAt": null,
    "lastRunStatus": null,
    "runCount": 0,
    "successCount": 0,
    "errorCount": 0,
    "webhookUrl": "https://flow.topolo.dev/api/hooks/whk_daffac264afb4bb49da6"
  }
}

HTTP 200. Read flows.get and compare exact intended fields/graph/trigger metadata; do not infer that a schedule or provider actually ran.

Another supported response

Actual exported Worker response with both local SQLite D1 databases and all committed migrations; synthetic Auth/grants and simulated Nexus/archive transport. No live credentials, provider calls, delivery, deployment or durable Workflow execution proof. Scenario: flows.update.

Input · payload.json:

{
  "flowId": "flow_d16b892d0e89474a8f24",
  "name": "Reviewed manual fixture",
  "status": "active"
}

CLI:

topolo actions validate app_topolo_flow.flows.update --data @payload.json --json
topolo actions plan app_topolo_flow.flows.update --resource-type workspace --resource-id "$FLOW_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_flow.flows.update --resource-type workspace --resource-id "$FLOW_WORKSPACE_ID" --data @payload.json --confirm --detail --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_flow.flows.update",
    "input": {
      "flowId": "flow_d16b892d0e89474a8f24",
      "name": "Reviewed manual fixture",
      "status": "active"
    },
    "resourceType": "workspace",
    "resourceId": "<id returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "flow": {
    "id": "flow_d16b892d0e89474a8f24",
    "orgId": "org_flow_fixture",
    "workspaceId": "ws_flow_fixture",
    "name": "Reviewed manual fixture",
    "description": null,
    "status": "active",
    "graph": {
      "nodes": [
        {
          "id": "trigger",
          "type": "trigger",
          "position": {
            "x": 0,
            "y": 0
          },
          "data": {
            "kind": "trigger.manual"
          }
        },
        {
          "id": "transform",
          "type": "logic",
          "position": {
            "x": 240,
            "y": 0
          },
          "data": {
            "kind": "core.transform",
            "config": {
              "assignments": {
                "message": "{{trigger.message}}"
              }
            }
          }
        }
      ],
      "edges": [
        {
          "id": "trigger-transform",
          "source": "trigger",
          "target": "transform"
        }
      ]
    },
    "triggerType": "manual",
    "webhookSecret": null,
    "scheduleCron": null,
    "scheduleNextRunAt": null,
    "eventType": null,
    "createdBy": "usr_flow_fixture",
    "createdAt": 1791218519766,
    "updatedAt": 1791218519868,
    "lastRunAt": null,
    "lastRunStatus": null,
    "runCount": 0,
    "successCount": 0,
    "errorCount": 0,
    "webhookUrl": null
  }
}

HTTP 200. Read flows.get and compare exact intended fields/graph/trigger metadata; do not infer that a schedule or provider actually ran.

Verify the result

  • Read flows.get and compare exact intended fields/graph/trigger metadata; do not infer that a schedule or provider actually ran.

Errors and recovery

  • Authentication token required (HTTP 401): Authenticate normally in the approved environment and organization, verify identity, then rediscover the action and its granted resource before retrying.
  • organization_required (HTTP 403): Authenticate into the specifically approved organization. Do not guess a different organization or bypass the refusal.
  • action_permission_required (HTTP 403): The credential lacks the exact published application permission. Stop and obtain authorized access; changing target ids cannot grant it.
  • workspace_required (HTTP 400): Discover an explicitly granted Flow workspace and bind its exact resource id.
  • graph_node_id_required (HTTP 400): Correct the exact graph structure before validating and planning again. Event triggers are unavailable in this source; use a supported manual, webhook or schedule trigger.
  • graph_node_id_duplicate (HTTP 400): Correct the exact graph structure before validating and planning again. Event triggers are unavailable in this source; use a supported manual, webhook or schedule trigger.
  • multiple_triggers_not_allowed (HTTP 400): Correct the exact graph structure before validating and planning again. Event triggers are unavailable in this source; use a supported manual, webhook or schedule trigger.
  • graph_edge_endpoint_required (HTTP 400): Correct the exact graph structure before validating and planning again. Event triggers are unavailable in this source; use a supported manual, webhook or schedule trigger.
  • graph_edge_endpoint_missing (HTTP 400): Correct the exact graph structure before validating and planning again. Event triggers are unavailable in this source; use a supported manual, webhook or schedule trigger.
  • graph_cycle_not_allowed (HTTP 400): Correct the exact graph structure before validating and planning again. Event triggers are unavailable in this source; use a supported manual, webhook or schedule trigger.
  • event_triggers_not_available (HTTP 400): Correct the exact graph structure before validating and planning again. Event triggers are unavailable in this source; use a supported manual, webhook or schedule trigger.
  • trigger_required (HTTP 400): Activation requires one trigger, at least one step and all steps reachable from that trigger with incoming edges. Correct and revalidate the graph before activation.
  • step_required (HTTP 400): Activation requires one trigger, at least one step and all steps reachable from that trigger with incoming edges. Correct and revalidate the graph before activation.
  • orphaned_step_not_allowed (HTTP 400): Activation requires one trigger, at least one step and all steps reachable from that trigger with incoming edges. Correct and revalidate the graph before activation.
  • action_not_allowed (HTTP 403): Remove or replace the graph node with an exact action this credential discovers through catalog.get, then validate and plan again.
  • catalog_unavailable (HTTP 502): Wait until credential-scoped service/action discovery is available; do not create a graph with guessed actions.
  • workspace_access_insufficient (HTTP 403): Stop when the selected workspace grant is insufficient. Obtain authorized read_write or admin access, or an Auth-introspected key with the correct workspace binding and workspace:write; do not widen context or retry with guessed ids.

Preserve the exact status, response, request id and resource context. Runtime input validation, authentication and platform resource resolution can refuse a request before the handler. Dynamic dependency messages are not stable provider error codes.

Recovery boundary

Read current state after an uncertain update. Restore a saved reviewed graph/settings through a separately authorized update; there is no version history or optimistic-concurrency token.

  • Get a flow: Read one automation graph and its trigger and run metadata in the workspace.
  • Run a flow: Execute a selected automation manually with an optional trigger payload.

Evidence

Captured from the actual exported Flow Worker with both local SQLite D1 stores and all committed migrations, synthetic Auth identity/grants and simulated Nexus, archive and Workflow-acceptance transports. Fixture credentials and identifiers authorize no live operation. No live provider invocation, credential storage, notification delivery, metering acceptance, durable Workflow execution, deployment, backup erasure or production completion is established by these captures. Original scenario labels and response digests are retained in the source fixtures.