Skip to content

Concepts

Flows, versions, orders, nodes and branches, waits, rollback and generations, and where each one lives.

A flow is a directed graph of nodes and edges, stored as JSON. Each node has a catalog type (commerce.reserve_inventory, control.approval, ai.router, …), a label and a config; each edge connects one output of its source node to a target node. The node catalog lists every type with its fields and outputs.

Each flow belongs to an order type: purchase_request, b2b_order, reorder, subscription, storefront_order. Every order type has a built-in flow, and you can add your own.

The editor saves a draft to D1 as you work. Publishing validates the draft and stores it as an immutable, numbered version. An order runs the version it started on (the latest, unless the API request names one), so editing or republishing a flow never changes an order in flight.

An order is one run of a published flow: an input (type, customer, currency, lines, an optional inbound document, free-form meta) plus the totals the flow computes. Its status is one of queued, running, waiting, completed, declined, cancelled, failed, rolled_back. The last five are terminal.

declined means a policy check or an approval said no. cancelled means a person or an API call cancelled it, or it reached an End node with that outcome. failed means a node threw or the order reached an End node with outcome failed; once the Workflow has run the order’s compensations the status becomes rolled_back, and it stays failed if the rollback itself fails.

Each order has:

  • an OrderLoop Workflow instance that interprets the flow. Each node is one durable, memoized step, so an order survives restarts and redeploys and can wait for days.
  • an OrderAgent, a Durable Object holding the order’s live state. It records what the Workflow reports, owns the order’s waits, and syncs every change to each open order page over a WebSocket.

A node finishes by choosing one or more of its outputs. Edges on the chosen outputs become active; edges on the others are skipped. A node runs once every incoming edge is resolved and at least one is active, so a node after an if/else runs whichever side was taken. A node whose inputs were all skipped is skipped too, and the skip carries on downstream. Nodes that become ready together run in parallel. The planner page has the exact rules.

Two node types stop and wait for the outside world:

  • Approval (control.approval) waits for a person to approve or reject, and takes its escalated branch if the timeout passes first.
  • Wait for event (control.wait_event) waits for a named business event such as payment.received, and takes timeout if it doesn’t arrive.

The OrderAgent records each open wait, and the dashboard, the REST API, a signed webhook or the order’s chat assistant can resolve it. See Approvals and events.

Reserving inventory, authorizing payment and creating a shipment each register a compensation on their step. When an order fails (an End node with outcome failed, or a node that throws), the Workflow runs those compensations in reverse order: stock is released, the authorization voided, the shipment cancelled. Cancelling an order does the same through the OrderAgent.

A Loop node repeats its body while a condition holds, up to a limit; the end of the body connects back to the loop’s next input. Subscriptions loop over billing periods and then continue as new: the run ends and a fresh Workflow instance starts on the same flow with the variables carried over, so the step history doesn’t grow without bound. Each run is a generation of the same order.

Expressions and text templates in node configs see the run context: order, vars (variables set by nodes and events), nodes (each node’s latest output, by id), input (the order’s meta) and now. See Expressions and policy rules.

Subscribers receive signed webhooks when an order is paid, invoiced, shipped or refunded, and whenever it ends. See Outbound webhooks.