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:
- The approval message is rendered with the current Flow context.
- The current execution context and next-step state are saved.
- The run moves to a waiting state and returns approval metadata, including
appRunId. - The user chooses approve or reject.
- The Flow resumes with an
approvalobject in context and follows the correct branch.
Step Configuration
{
"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
rejectNextStepIdwhen one is configured. - If no reject branch exists, rejection falls back to
nextStepId.
After resume, downstream steps can read:
{ {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:
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:
POST /v1/flowrun/resume/:appRunIdApprove:
{
"decision": "approve"
}Reject:
{
"decision": "reject"
}For a Flow paused inside a first-party Peer conversation, the dashboard route can resume the message approval:
POST /v1/peer/message/:messageId/resume{
"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.

