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.
flow.slug from your .failpath/flows.json. Prefer failpathFlows from .failpath/sdk.ts so TypeScript autocompletes valid flow slugs. 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 queue any events. Events are queued 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 generated key from failpathFlows or the raw sdkStepKey from flows.json as the first argument.
run.step() executes:
1
running event queued
Before your function is called, Failpath queues a
running event for this
step.2
Your function runs
The wrapped function executes normally. Its return value is passed through
so you can use it in subsequent steps.
3
success or error event queued
If the function resolves, Failpath queues a
success event. If it throws,
Failpath queues an error event and rethrows the original error so your
application continues to behave as expected.failpath.flush() before a short-lived process exits, or use a runtime waitUntil hook when one is available.
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.
skipped event for that step without calling any function. Use it for conditional branches where a step legitimately does not apply to this run.
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().
flowKey, the same runId you use for the rest of the run, the step’s generated key as stepKey, and one of "running", "success", "error", or "skipped" 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.