Runs
A run represents one end-to-end execution of a flow. You create a run by callingfailpath.run() with the flow’s slug and a runId that uniquely identifies this execution.
"checkout" — must match the flow.slug from your .failpath/flows.json. The runId ties all of the step events for this execution together on the dashboard. Use the natural identifier already available in your application: a request ID, a job ID, or a webhook delivery ID all work well.
A run object is lightweight — creating it does not send any events. Events are only sent when you call run.step() or run.skip().
Steps
A step is a named unit of work within a run. You instrument a step by wrapping your business logic inrun.step(), passing the step’s sdkStepKey from flows.json as the first argument.
run.step() executes:
running event sent
Before your function is called, Failpath sends a
running event for this
step to the dashboard.Your function runs
The wrapped function executes normally. Its return value is passed through
so you can use it in subsequent steps.
Skipping steps
Not every step in a flow runs on every execution. When a step is intentionally not executed in a particular run, callrun.skip() so the dashboard can show it as skipped rather than missing.
Recording steps manually
When you cannot wrap a function directly — for example, a step that runs in a separate service, a third-party callback, or an out-of-band process — usefailpath.recordStep() to send an event manually instead of using run.step().
flow.slug as flowKey, the same runId you use for the rest of the run, the step’s sdkStepKey as stepKey, and one of "running", "success", or "error" as status. This lets you fill in parts of a flow that the SDK cannot instrument automatically so the dashboard graph shows the full picture.
Best practices
Wrap business steps
Instrument the meaningful stages of your process — charge a card, send an
email, update an order — not low-level helpers or individual database calls.
Steps should map to the nodes visible on your flow graph.
Let errors bubble
You do not need to catch errors inside a
step() callback. The SDK records
the error event and rethrows the original error automatically, so your
existing error handling stays intact.