Step-Through Execution
Drive a published flow one step at a time — inspect, edit, and continue. The pattern, the loop, and full client code.
Some flows you want to run end-to-end (/execute). Others — debugging
sessions, human-in-the-loop UIs, "let me edit step 2's output and re-run
step 3" — need to pause between steps. That is what
POST /seq/{org}/{project}/{flow}/step does.
This guide walks through the pattern, the client loop, and the two override planes. For the protocol-level spec see Step-Through Execution API.
Mental Model
Three things to internalize:
- The server is stateless between calls. It resolves the flow tree, executes one step, streams the SSE events, then drops everything. Your client is the source of truth for where you are in the flow.
- You always send everything you've collected so far. Each call
POSTs the full
accumulatedOutputsmap. The server uses it to derive the next step'spipeline_input. - The cursor is the request, not a server-side handle. The
executionIdonly ties the run to aFlowRunrow for tracking and billing. It is not a session you can lose.
When to Use This Endpoint
| You want to… | Use |
|---|---|
| Get a final result, end-to-end | /execute |
| Long-running, polled | /jobs |
| Show each step's output in a UI before continuing | /step |
| Edit a block's prompt mid-run and re-execute downstream | /step with blockOverrides |
| Replay a flow with one step's output replaced | /step with inputOverrides |
| Run from step N to the end on demand | /step with runRemaining: true |
The Two Override Planes
These are independent and frequently confused.
inputOverrides — replace a prior step's output
Use when you want to lie to a downstream step about what an earlier step produced.
blockOverrides — replace a block's configuration
Use when you want to change how a block runs — its prompt, model, or schemas — before executing it.
You can use both in the same call. They apply at different layers and do not interact.
A Complete Client Loop
The client always does the same thing each turn: POST, parse SSE events, merge outputs, decide whether to continue.
Editing an Earlier Output Mid-Run
If your UI lets the user edit step A's output before continuing, send
the edit on the next call via inputOverrides. The server merges it
on top of accumulatedOutputs before deriving the next step's input.
You do not need to mutate accumulatedOutputs — keeping the original
output there and overriding it on the next call leaves you with a clean
"original vs. edited" trail in client state.
Editing a Block Before It Runs
If your UI lets the user tweak block B's prompt before it executes,
send blockOverrides on the call that runs B:
blockOverrides is re-applied every call — it is not persisted on
the server. If you want the override to last across the rest of the
session, your client must keep sending it.
Run-To-End From Any Step
Once the user is happy through step N, finish the rest in one shot without further pauses:
You'll get step_progress events between steps and a final
run_completed.
Loops Are Atomic
A loop step runs all iterations in one call. You cannot pause
inside a loop. The cursor pauses between a loop step and whatever
comes after it, never partway through the iterations. Plan UX
accordingly.
Handling STALE_TREE
If someone re-publishes the flow while a session is mid-run, the step
ids in your client-side accumulatedOutputs may not exist in the new
tree. The server returns 400 STALE_TREE with the current plan in
detail.steps. Recover by:
- Show the user that the flow changed.
- Reset client state (drop
executionId,cursor,accumulatedOutputs). - Start a new session from
stepIndex: 0.
To avoid this entirely, pin to a version:
A pinned version's tree is immutable.
Why does the server re-resolve the tree on every call? It's a small
DB read and keeps the server stateless. For human-paced step-through
this overhead is negligible. If you ever drive /step programmatically
at high QPS, prefer runRemaining: true so one HTTP call covers many
steps.
Common Mistakes
- Forgetting to send
accumulatedOutputson later calls. The server has no memory of prior calls. Without it, step N can't derive itspipeline_input. - Sending
messageon every call. It's required atstepIndex: 0and ignored after. Sending it later is harmless but a code smell — it suggests the client thinks the server keeps state. - Using the unversioned URL for long sessions. A re-publish triggers
STALE_TREE. Prefer/v{n}/stepfor any session that may outlive a deploy. - Trying to use
v0(draft). Rejected withINVALID_VERSION. Step- through requires a stable tree. - Treating
executionIdas a session token. It's aFlowRunidentifier for billing/tracking. Loss ofexecutionIdis recoverable by starting a new run with the sameaccumulatedOutputs(you'd just lose the original FlowRun's tracking — the data is intact).
See Step-Through Execution API for the full request/response reference.