Skip to content

Building flows

A flow is a chain of API steps you can run from the UI, the CLI, the API, CI, or a recurring schedule. You build flows on a visual canvas: drag nodes from the palette, connect them with edges, then press Run flow. Each run is recorded as an execution in Run history.

The canvas has nine node kinds, each with its own configuration UI:

NodeWhat it does
RequestSends an HTTP request. Configure method, URL, headers, and body. Attach outputs and assertions to its response.
DelayWaits for a fixed duration before the next node runs. Useful when the API you are testing settles asynchronously.
ModuleRuns another flow as a child execution step. This is flow reuse: pass values in with input bindings, read values back with output bindings.
Set VariableSets a variable for downstream nodes to reference.
AssertA standalone assertion step, checked and recorded like any other assertion.
BranchRoutes the flow down conditional paths.
LoopRepeats a section of the flow.
PollRepeats a request until a condition is met.
SSESubscribes to a server-sent-events stream.

The CLI’s flows node add authors request, delay, and module nodes; the other six kinds are authored on the canvas.

A checkout-smoke flow for a payments API might look like:

  1. POST /auth/token — Request node, asserts statusCode equals 200
  2. POST /payments — Request node, extracts $.id into payment_id
  3. Delay 2s — Delay node, waits for settlement
  4. verify-refund — Module node that runs a shared refund-check flow

Edges connect nodes along success or error paths, so a failing request can route to different downstream steps than a passing one.

Each node also has a run_when condition:

  • on_success (default) — the node runs only when its upstream path succeeded.
  • always — the node runs even after an upstream failure. Use this for cleanup steps, such as deleting the test payment a failed run left behind.

Nodes that do not run are marked skipped, and the execution records a skip_reason plus any missing_inputs, so you can see exactly why a step was bypassed.

Reference values anywhere in a request with {{double_brace}} syntax:

Request, Delay, and Module nodes can also be scripted with the CLI using echopoint flows node add:

Terminal window
# Request node
echopoint flows node add <flow-id> --type request --name "Create payment" \
--method POST --url "{{BASE_URL}}/payments" \
--headers '{"Authorization": "Bearer {{API_TOKEN}}"}' \
--body '{"amount": 4200, "currency": "eur"}'
# Delay node (duration in milliseconds)
echopoint flows node add <flow-id> --type delay --name "Wait for settlement" \
--duration 2000
# Module node: run another flow as a child step
echopoint flows node add <flow-id> --type module --name "verify-refund" \
--flow-id <child-flow-id> \
--input payment_id={{payment_id}} \
--output refund_status=refund_status

Connect nodes with edges, or let --after wire the edge for you when adding a node:

Terminal window
echopoint flows edge add <flow-id> --from create-payment --to verify-refund
# A cleanup step that runs even when upstream failed
echopoint flows node add <flow-id> --id cleanup --type request \
--run-when always --after verify-refund \
--name "Delete test payment" --method DELETE \
--url "{{BASE_URL}}/payments/{{payment_id}}"

Before running a flow in CI, check that its structure is sound — every referenced node exists, bindings resolve, edges connect real nodes:

Terminal window
echopoint flows validate <flow-id>

Export the full flow definition as JSON to review it or keep a copy alongside your code:

Terminal window
echopoint flows export <flow-id>

The Flow Library organizes flows into folders. Create a folder, move flows in bulk, or drag a flow onto a folder to move it. The CLI mirrors this with the flows folder commands.