Skip to main content
Each section below is one task, with a complete workflow or client call you can paste into the quickstart runner and run as-is. Nothing is elided. Every link goes to the reference for that capability. Not sure which you need? Start with your goal.

Retry a flaky call, fail fast on a bad one

A step retries on its policy. NonRetriableError ends the run on the first attempt - retrying a declined card cannot fix it - and RetryAfterError retries on a delay the upstream dictated.
onFailure runs durably after the run has exhausted its retries and failed. It receives the original event plus ctx.error, and cannot un-fail the run. Retries

Fan one event out to many workflows

Every workflow subscribed to user.signup gets its own run. A CEL if filter narrows a subscription to the events that match it.
A free signup starts one run; a pro signup starts two. Events · Triggers

Pause for hours, then continue

step.sleep parks the run - it holds no process and no connection. step.waitForEvent parks it until a matching event arrives, and resolves to null if the timeout matures first.
Steps

Run on a schedule

A cron trigger needs no event. singleton: { mode: "skip" } drops a tick that would overlap a run still in flight.
Each scheduled run’s input is { cron, scheduledFor }. Triggers

Shape a burst of events into runs

Flow control is declared on the workflow and applied before a run starts. debounce coalesces a burst into one run carrying the last event’s data; batch accumulates events into one run delivered as ctx.events; rateLimit drops what is over the cap.
The eight controls - concurrency, throttle, rateLimit, debounce, batch, priority, singleton, idempotency - and what each does to an event over its cap: Flow control

Call a child workflow, in parallel

step.runWorkflow starts another workflow as a child run and returns its output. Steps that do not depend on each other run concurrently under Promise.all.
Passing app addresses the child to that app exactly; omit it to resolve the name in the caller’s app first. Workflows

Make a model call durable

step.ai.generate is one model call as a step: it runs once, and a retry after a crash returns the recorded result instead of paying the model again. The call happens in your runner, with your provider key.
A failed validate triggers a durable re-ask, itself a memoized step. AI · step.ai reference

Park a run on a human decision

step.approval suspends the run at its checkpoint, holding no worker, until someone approves or denies. The decision resumes the run from that checkpoint and is memoized, so a replay never re-parks.
The decider may edit the proposed args; decision.args are the effective ones. Approvals

Log, then watch a run live

ctx.log writes structured, leveled lines onto the run. runs.watch streams the run’s timeline - status transitions, step transitions, and log lines - and ends on its own when the run is terminal.
runId is absent when the event started no run - it was deduped, dropped, debounced, or batched by a flow-control policy. Logging · Realtime

Replay a finished run

A replay forks a new run from the original’s trigger and links it back through replayOf; it does not mutate the original. retryFromStep carries the steps before the named one as memoized and resumes there, so completed work is not re-executed.
Every cancel, pause, resume, replay, and retry is recorded with the API key that performed it. Control API

Receive and send webhooks

ctx.webhook.send is a durable outbound delivery: retried on a backoff, with every attempt recorded in the delivery log.
Inbound is the mirror: register a receiver in the console and a signature-verified POST becomes an event that starts a run. Webhooks

Drive it from anywhere else

No SDK required. Every run, event, and control action is an HTTP endpoint your key can call, and the same surface is exposed as MCP tools for an agent or editor.
REST API · MCP