Skip to content

User Approval in Flows

User Approval lets a Flow pause before a sensitive action and wait for a human decision. It is useful for human-in-the-loop workflows where automation should not continue until someone approves or rejects the next step.

How It Works

When a Flow reaches a user-approval step:

  1. The approval message is rendered with the current Flow context.
  2. The current execution context and next-step state are saved.
  3. The run moves to a waiting state and returns approval metadata, including appRunId.
  4. The user chooses approve or reject.
  5. The Flow resumes with an approval object in context and follows the correct branch.

Step Configuration

json
{
  "type": "user-approval",
  "name": "Confirm Action",
  "data": {
    "message": "Approve sending this quote to { {customer.email} }?"
  },
  "nextStepId": "send-email",
  "rejectNextStepId": "cancelled"
}

In the Flow editor, type template braces without spaces.

Branching

  • Approve follows the step's normal nextStepId.
  • Reject follows rejectNextStepId when one is configured.
  • If no reject branch exists, rejection falls back to nextStepId.

After resume, downstream steps can read:

text
{ {approval.decision} }
{ {approval.decidedAt} }
{ {approval.decidedBy} }
{ {approval.message} }

When to Use

Use User Approval before actions such as:

  • Sending external emails or messages.
  • Publishing content.
  • Running costly or irreversible tool actions.
  • Submitting payments, refunds, or account changes.
  • Continuing a compliance-sensitive workflow.

User Experience

In a Peer conversation, the approval appears as a pending action on the assistant message. The user chooses approve or reject, then the same message is updated with the resumed Flow result.

Example Flow:

text
Trigger: peer.message
  -> Prepare quote
  -> User Approval: "Send quote for { {quote.total} }?"
     Approve -> Send email -> Final: "Quote sent"
     Reject  -> Final: "Quote was not sent"

Programmatic Resume

When a direct Flow execution pauses, resume it through the Flow run endpoint:

http
POST /v1/flowrun/resume/:appRunId

Approve:

json
{
  "decision": "approve"
}

Reject:

json
{
  "decision": "reject"
}

For a Flow paused inside a first-party Peer conversation, the dashboard route can resume the message approval:

http
POST /v1/peer/message/:messageId/resume
json
{
  "decision": "approve"
}

Client conversation resume endpoints are primarily used for client-tool results. Use the appRunId resume endpoint when you are integrating approval decisions outside the built-in chat UI.

Best Practices

  • Put the approval immediately before the action it protects.
  • Write concise messages that include the concrete consequence.
  • Always test both approve and reject branches.
  • Add a reject branch when cancellation needs a specific response or cleanup step.
  • Return a clear Final step message after the Flow resumes.

Built with VitePress