Skip to content

Keep a human in the loop

Most of your automations should run without interruption. But some decisions are genuinely yours to make — approve this payment, confirm this vendor, sign off on this outreach campaign. Routario handles that through the Inbox: the queue where work that needs a human judgment call waits, gets answered, and is sent back into motion.

This guide shows you how to wire up those human-in-the-loop moments: a single approval gate, a branch on the answer, and a parallel sign-off from several people.

For the full picture on channels, lifecycles, and escalation behaviour, see Asking a person.

Ask a person is the building block. Drop it anywhere in a flow and it does three things: pauses the run, delivers the question to someone, and resumes the flow when they answer.

The pause is real and durable — the run holds no thread, survives a server restart, and picks up exactly where it left off.

Set a response type to decide what the person sees:

Response typeWhat they see
Yes / NoTwo buttons — good for approvals
ChoiceA dropdown built from the options you list
Free textA text box
AcknowledgeA single “got it” button
Integer / DecimalA number field
Image / PDF / FileA file upload

Set a channel to decide where the question reaches them:

  • Inline (default) — appears right on the run’s canvas, for someone who started the flow and is watching it.
  • Modal — a pop-up on the canvas. Same idea as inline, just surfaces as a dialog.
  • Notification — the bell announces it; the person answers it from their Inbox, not the bell itself. Best when they’re in Routario but not necessarily watching this particular run.
  • Email / WhatsApp / Slack — reaches them off-platform via the message itself.

The answer flows downstream as {{ <label>.response }}. Label the step approval and the rest of the flow can read {{ approval.response }}.

An ask alone doesn’t change what happens next — you need a Branch step to act on the answer.

Branch evaluates a condition and follows one of two paths: the YES arm or the NO arm. Wire the two arms to different outcomes and merge them back together downstream.

Example condition after a yes/no ask labelled approval:

{{ approval.response == "yes" }}

If the manager approved: continue. If not: skip to the next record, send a notification, or stop entirely — your choice.

Sometimes one approval isn’t enough — you need a manager and a finance lead to both sign off before the flow moves on. Do this with fire-and-continue asks and a Checkpoint.

Here’s the pattern:

  1. Add an Ask a person step. Turn on fire-and-continue, set the channel to notification, and give it a label — say manager_approval.
  2. Add a second Ask a person step the same way — label it finance_approval.
  3. Add a Checkpoint step. Add a signal condition for each ask (from_step: manager_approval, from_step: finance_approval). Set the policy to all (wait for both) or any (proceed when either answers).

With fire-and-continue, both questions go out immediately and the flow keeps running past the asks — it only parks at the Checkpoint. When both answers are in, the Checkpoint unblocks and downstream steps can read {{ checkpoint.manager_approval }} and {{ checkpoint.finance_approval }}.

Set a timeout on the Checkpoint so a slow responder doesn’t block the flow indefinitely. When the timeout fires, {{ checkpoint.reason }} equals "timed_out" — you can branch on that to send a reminder or escalate. (For a single ask that just needs a reminder-then-hand-off, see escalation below — it’s built into the ask itself, no Checkpoint required.)

A flow that finds invoices over a threshold, asks a manager to approve each one, and only marks them for payment if approved.

1. Schedule trigger. Set to run each morning.

2. Find large invoices. Add a Find records step filtered to invoices over your threshold. Label it invoices.

3. Loop over each invoice. Wrap the next steps in a For each over {{ invoices }}. Each invoice is available inside the loop as {{ loop.item }}.

4. Ask for approval. Add an Ask a person step. Set the question to something like:

Invoice {{ loop.item.number }} from {{ loop.item.vendor }} is {{ loop.item.amount }}.
Approve for payment?

Set response type to Yes / No, channel to notification, and assign it to your finance manager. Label the step approval.

5. Branch on the answer. Add a Branch step with the condition {{ approval.response == "yes" }}.

  • YES arm — mark the invoice as approved (update the record, send an email, or trigger a payment step).
  • NO arm — send the manager a notification asking them to add a note, or simply skip to the next invoice.

6. Merge and continue. Reconnect the two arms and let the loop move on to the next invoice.

A worked example: capturing why an invoice was rejected

Section titled “A worked example: capturing why an invoice was rejected”

A plain Yes / No ask tells you that someone rejected something — not why. For an approval that gets rejected often, that missing context means someone has to go track the person down and ask. You can capture the reason automatically by chaining a few more steps onto the NO arm above.

Building on the invoice-approval example: instead of just notifying the manager on rejection, send them a follow-up asking why, wait for their reply, and save it onto the invoice record.

1. Branch on rejection. After the approval ask, add a Branch with the condition {{ approval.response == "no" }}.

2. Send a “why?” email. On the rejected arm, add a Send email step to the same manager:

Subject: Why was invoice {{ loop.item.number }} rejected?
Body: You rejected the invoice from {{ loop.item.vendor }} for
{{ loop.item.amount }}. Reply to this email with the reason so we can
record it.

3. Wait for the reply. Add a Wait step configured to pause until a reply arrives on that email’s thread, with a timeout — say, 3 days — so a manager who never replies doesn’t leave the flow stuck. Set the timeout to continue rather than fail, so the flow still finishes even with no reason on file.

4. Save the reason. Add an Update record step and write the reply’s text (or a placeholder like “No reason given” if the wait timed out) into a reject_reason column on the invoice record.

The result: your invoice records carry a genuine paper trail — not just approved or rejected, but rejected, because the PO number didn’t match — without anyone having to manually chase the reason down.