Workflow Builder

The visual canvas for building integration workflows in Cockpit

This page is for integration engineers about to build their first workflow. It walks you through what the canvas actually does, how to think about nodes and edges, and the practical steps from "blank workflow" to "deployed and running."

If you haven't read Dual-Engine Architecture yet, that's the conceptual background — but you don't need it to follow along here. The canvas is hands-on; the architecture explains why the canvas works the way it does.

The canvas, conceptually

A workflow is a graph. Nodes are operations (HTTP request, JSON transform, conditional check, file download, …). Edges connect nodes — they're how data flows from one step's output into the next step's input.

The canvas in Cockpit has three parts. The main area is the graph itself, where you place and connect nodes. The left side is the node palette — every node type you can add to the graph. The right side is the configuration panel, which becomes active when you select a node and shows that node's settings (URL, method, headers, body for HTTP; mapping rules for transforms; cron expression for schedules).

The mental model is similar to other visual workflow tools you might have used — Zapier, n8n, Workato — but with two important differences:

  1. The same workflow definition can run on either of two engines (durable async, or sync in-process). You pick when you deploy.
  2. Workflows are deployed as JSON definitions, not as imperative steps. That means you can version them, diff them, store them in Git, and apply them through the CLI alongside your other app code.

Building a workflow, end to end

Here's what the typical first-workflow flow looks like in practice. Suppose you're building the nightly SAP order sync from the Integration Studio overview.

1. Add a trigger

Every workflow has exactly one trigger — the thing that starts it. You drag a Schedule trigger onto the canvas from the left palette. With the trigger selected, the configuration panel on the right asks for a cron expression. You enter 0 2 * * * (every day at 02:00) and a timezone.

2. Fetch the data

You drag an HTTP Request node next to the trigger and connect them with an edge. In the config panel:

  • Method: GET
  • URL: {{secrets.SAP_BASE_URL}}/orders?since={{$today}}
  • Headers: Authorization: Bearer {{secrets.SAP_TOKEN}}

The {{secrets.SAP_BASE_URL}} and {{secrets.SAP_TOKEN}} references are filled in from the workflow's encrypted secrets store at runtime — neither is ever in the workflow definition itself. (See Expression Syntax for what's available in these curly-brace references.)

3. Transform the response

You drag a JSON Transform node and connect it to the HTTP Request's output. The transform's job is to reshape SAP's response into the format your internal orders API expects. The config panel lets you write a mapping rule that picks fields out of the input and assembles them into the output shape.

4. Push to the catalog

You drag a second HTTP Request node for the POST to your internal orders API. URL, method (POST), and body (which references {{steps.2.outputs}} — the transform's output) go into the config panel.

5. Test before deploying

There's a Test button on the canvas. Clicking it runs the workflow once with the configuration as-is. For async workflows, you see the run history appear in the side panel — each step's input, output, and status. For sync workflows, you get the response back immediately.

This step is what separates Integration Studio from "I'll deploy it and watch the logs." You can see exactly what each node sees and outputs, before anyone in production depends on it.

6. Deploy

When the test run looks right, click Deploy. For async workflows, this registers the workflow with the durable engine and (if a Schedule trigger is configured) starts the schedule. For sync workflows, it exposes the workflow at an HTTP endpoint that storefronts and other services can call.

That's the full loop: add trigger, add nodes, configure them, wire them up with edges, test, deploy. Most workflows look like this; the differences are in how many nodes and how complex the configuration gets.

How data flows between nodes

This is the part most newcomers get wrong on their first try, so it's worth being explicit.

Every node receives input from its predecessor on an edge, and produces output. Output is named — typically outputs.body for HTTP responses, outputs.headers for the headers, and similar for other nodes. You access a previous step's output via expression syntax: {{steps.N.outputs.body}} where N is the step index (0 for the trigger, 1 for the first node after, …).

A node further downstream can reference any previous step's output, not just the immediate predecessor. So in the example above, step 3 (transform) can reference both {{steps.0.outputs}} (the trigger's input data) and {{steps.1.outputs.body}} (the HTTP response).

For the full reference of what you can write inside {{ ... }}, see Expression Syntax.

Sync versus async — which engine to pick

You choose the engine when you deploy the workflow, not when you design it. The same canvas, same nodes, same edges — different runtime guarantees.

Pick async (durable) when:

  • The workflow takes more than a few seconds (most batch and scheduled imports).
  • Durability matters more than latency — if the worker crashes, the workflow should resume, not start over.
  • You want automatic retries with exponential backoff on transient failures (network blips, third-party timeouts).
  • Triggers are Schedule or Manual, or Webhook with a 202-accepted response pattern.

Pick sync (in-process) when:

  • The caller is waiting on the screen — a buyer on a product page, a storefront rendering checkout.
  • Sub-100ms latency is a requirement.
  • Best-effort is acceptable — if something fails, you'd rather return a clear error to the caller than retry silently.
  • The trigger is a Webhook or Manual call where the caller expects a real response.

A useful heuristic: if you'd implement this with a background job in a normal application, pick async. If you'd implement it with a direct API call, pick sync.

Error handling

Different error model per engine.

Async workflows: when a node fails, the engine retries it (configurable retry policy, exponential backoff, max retries). When the retry budget is exhausted, the workflow is marked failed and shows up in Cockpit with the full failure context. The customer can click Retry to start the failed step over with the same inputs.

Sync workflows: when a node fails, the workflow stops and returns an HTTP error response. There's no automatic retry — the caller decides what to do (retry from the caller side, fall back to cached data, show an error). This is the right model for sync because the caller is waiting on the response and a silent retry just delays a clear failure.

Where to go next

  • Node Types — Every node type, what it does, how to configure it.
  • Triggers — The three trigger types in detail, with use-case guidance.
  • Expression Syntax — Reference for everything you can write inside {{ ... }}.
  • Dual-Engine Architecture — The conceptual deep dive into why the two engines exist.
Was this page helpful?