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 request, reuse, and control-flow nodes with their 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.
Webhook WaitWaits for matching captured webhook events during a running flow.

The CLI’s flows node add authors request, delay, module, and webhook_wait nodes; use the canvas or full flow definitions for the other kinds.

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:

  • Outputs extracted from earlier nodes, such as {{create_payment.payment_id}} from the node with ID create_payment
  • Environment variables like {{BASE_URL}} and {{API_TOKEN}}
  • Dynamic variables like {{$uuid}} for generated test data

Request, Delay, and Module nodes can also be scripted with the CLI. This example assumes an existing parent flow and a child refund-check flow. Replace <flow-id> and <child-flow-id> with their IDs, configure BASE_URL and API_TOKEN for a test API, and make sure the child accepts a payment_id input and has a node with ID check_refund that exposes a refund_status output. The illustrative API below creates a payment at POST /payments and returns its ID in $.id.

Use explicit node IDs so output references and edges point at the nodes you create:

Terminal window
# Create a payment and name the node create_payment
echopoint flows node add <flow-id> --type request --id create_payment \
--name "Create payment" --method POST --url "{{BASE_URL}}/payments" \
--headers '{"Authorization": "Bearer {{API_TOKEN}}", "Content-Type": "application/json"}' \
--body '{"amount": 4200, "currency": "eur"}'
# Declare the output referenced by the later nodes
echopoint flows node output add <flow-id> create_payment \
--name payment_id --extractor json_path --path "$.id"
# Delay node (duration in milliseconds)
echopoint flows node add <flow-id> --type delay --id wait_for_settlement \
--name "Wait for settlement" --duration 2000
# Module node: run the prepared child flow
echopoint flows node add <flow-id> --type module --id verify_refund \
--name "Verify refund" --flow-id <child-flow-id> \
--input 'payment_id={{create_payment.payment_id}}' \
--output refund_status=check_refund.refund_status

Connect those exact node IDs in order. For the cleanup node, --after creates the success edge as part of the add command:

Terminal window
echopoint flows edge add <flow-id> --from create_payment --to wait_for_settlement
echopoint flows edge add <flow-id> --from wait_for_settlement --to verify_refund
# Cleanup can run after an upstream failure when payment_id is available
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/{{create_payment.payment_id}}" \
--headers '{"Authorization": "Bearer {{API_TOKEN}}"}'

Only use this cleanup when your test API supports deleting that resource. If the create step never produced payment_id, cleanup records a skip reason instead. Add assertions for the status codes and business values your API is expected to return before relying on this flow as a test.

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>

Inspect the saved flow, including its definition, as JSON:

Terminal window
echopoint flow view <flow-id> -o json

CLI v2 has no dedicated flow export command. The JSON above is an API detail response, not a guaranteed import-ready file for flow create --file.

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.