Approvals — human-in-the-loop
Some steps should not be automatic: shipping an order over a threshold, sending the customer email, deleting production data. The Approval node parks the run until a person decides — and every pending gate across your whole fleet lands in one inbox in the Nucleus header.
The gate
Drop Approval (Logic group) where the decision belongs. Its config:
| Property | Meaning |
|---|---|
title | The question, verbatim, on the approval card — “Approve order?” |
description | Context for the decider |
decisions | The options the decider picks from — default Approve, Reject. Each becomes its own output port, so add your own (Decline, Defer, Retry) for a multi-way human gate |
timeoutMs | 0 = wait indefinitely; otherwise the gate expires after this long |
onTimeout | What expiry does: approve, reject, or error (fail the run into its recovery lane) |
With the default decisions the node has two outputs — approved and rejected — so both outcomes are wires, not status codes. Every decision you add is another wire, and the decide endpoint (and the inbox) accepts any configured option, not just the classic pair.
A real example
The shipped Approval Gate demo gates an HTTP-triggered order flow with four nodes:
- an HTTP Trigger listening for
POST /orders, - an Approval gate titled “Approve order?”, its description written for the human (“A new order needs a human decision before it ships”), no timeout,
- an HTTP Response with status
202wired to the gate’s approved port, and - an HTTP Response with status
403wired to rejected.
The two outcomes are two visibly different wires on the canvas — the Approval node reference shows the wired capture and a real approved run’s data.
POST an order to /orders and the caller waits while the run parks at the gate. Approve → the
caller gets 202; reject → 403. (An HTTP Response node does not release the caller earlier: on a
deployed host the reply is built from that node’s recorded output once the run reaches a terminal
state, so a workflow containing one holds the connection through the park. To not make the caller
wait for a human, leave the response node out and take the
async receipt instead.)
Here is the live loop, recorded end to end — an order arrives, the inbox bell lights up, Approve, and the parked run resumes:
The host’s own dashboard shows the same gate in its Pending approvals panel — see the capture in the Hosts guide.
The fleet-wide inbox
The bell in the Nucleus header polls every pending gate across every authorized host. Each card shows the gate’s title and description, the workflow and app, the host, how long it has waited, and a live countdown when a timeout is set. Approve / Reject (with an optional note) resumes the parked run immediately — the deciding user’s name is recorded with the decision.
Deciding requires the executor role; viewers see the inbox read-only. Hosts also show their own apps’ pending gates in a panel on the host dashboard.
Where the run actually waits
On a deployed host the parked run lives in the host’s embedded engine; the host serves its pending-gate listing and decisions.
Pending gates don’t survive a host restart. A restarted host starts clean and the parked run is gone — the gate cannot be rebuilt, because a run is only written to the durable record once it reaches a terminal state. What the caller sees depends on how the webhook answers:
- The default (async) webhook isn’t holding a connection at all — it was handed
202 { runId, status, statusUrl }before the gate was ever reached. After a restart its status URL returns404: the run neither succeeded nor failed, it stopped existing. - A workflow with an HTTP Response node is on the synchronous contract, and the host only builds that reply once the run reaches a terminal state — so a caller parked at a gate is still holding the connection. A restart drops it, and there is no reply and no run left to collect. The synchronous contract is the worse one to be on here, not the better one.
If a gate may stay open across a deploy or a restart, don’t rely on the run surviving it: have the workflow record its own state (a database row, a queue message) before parking, so the decision has something durable to land on.
In the editor
Approval gates work in test runs too — the run pauses, Studio surfaces the gate, and you decide it inline. Same node, same semantics, before anything is deployed.
Agent tool calls can wait for you too
The gate pattern extends to AI: the AI Agent node’s approval property
(off / write / all) parks the agent’s tool calls for a human decision through the same
machinery — an agent can research freely but needs a sign-off before it writes. The pending
call surfaces like any other gate, with its own timeout policy.