Skip to content

User Approval in Flows

The User Approval feature allows flows to pause execution and wait for human confirmation before proceeding with critical actions. This provides a "human-in-the-loop" capability for workflows that require manual oversight.

Overview

User Approval enables you to:

  • Pause Execution: Stop flow execution at any point
  • Request Confirmation: Show users a custom approval message
  • Branch on Decision: Route flow based on approve/reject choice
  • Resume Safely: Continue execution exactly where it paused
  • Maintain Context: All variables and state are preserved

When to Use

User Approval is ideal for:

  • ✅ Critical operations (deleting data, financial transactions)
  • ✅ Compliance requirements (approval workflows, audit trails)
  • ✅ User consent (GDPR, privacy confirmations)
  • ✅ Cost-sensitive actions (API calls with charges)
  • ✅ Irreversible operations (sending emails, publishing content)

Quick Start

1. Add User Approval Step

  1. Open your flow in the Flow Editor
  2. Click Add Step where you want to pause for approval
  3. Select User Approval from the Workflow category
  4. Configure the approval message

2. Configure the Step

Basic Configuration:

json
{
  "type": "user-approval",
  "name": "Confirm Action",
  "data": {
    "message": "Are you sure you want to proceed?"
  }
}

With Context Variables:

json
{
  "type": "user-approval",
  "name": "Confirm Deletion",
  "data": {
    "message": "Delete {{count}} items from {{category}}? This cannot be undone."
  }
}

3. Connect Paths

The User Approval step automatically creates two output paths:

  • ✅ Approve Path (Green): Connect to steps that should run if approved
  • ❌ Reject Path (Red): Automatically goes to a final step (or connect to custom rejection logic)

4. Test Your Flow

  1. Assign the flow to a peer
  2. Send a message that triggers the flow
  3. When the approval step is reached:
    • Flow execution pauses
    • User sees the approval message with buttons
  4. Click Approve or Reject
  5. Flow resumes and completes

User Experience

In Chat Interface

When a flow reaches a user approval step, users see:

┌─────────────────────────────────────┐
│ Delete 50 items from Electronics?  │
│ This cannot be undone.              │
│                                     │
│  [Approve ✓]    [Reject ✗]         │
└─────────────────────────────────────┘

After clicking:

  • Button shows loading state
  • Flow resumes execution
  • Final result is displayed

In WebChat

The approval UI integrates seamlessly with WebChat:

html
<!-- Approval appears inline in conversation -->
<div class="approval-box">
  <p>Approve payment of $1,250.00 to vendor?</p>
  <button onclick="approve()">Approve</button>
  <button onclick="reject()">Reject</button>
</div>

Flow Examples

Example 1: Simple Approval

yaml
Trigger: User message

Parse Request (extract item details)

User Approval: "Delete item {{itemName}}?"
    ├─ Approve → Delete Item → Final (Deleted successfully)
    └─ Reject → Final (Deletion cancelled)

Example 2: Multi-Step with Approval

yaml
Trigger: Form submission

Validate Data

Calculate Cost ({{totalCost}})

User Approval: "Process payment of {{totalCost}}?"
    ├─ Approve → Charge Payment
    │              ↓
    │          Send Confirmation Email
    │              ↓
    │          Final (Payment successful)
    └─ Reject → Final (Payment cancelled)

Example 3: Multiple Approvals

yaml
Trigger: Complex workflow

Prepare Action

User Approval 1: "Approve data changes?"
    ├─ Approve → Apply Changes
    │              ↓
    │          User Approval 2: "Finalize and publish?"
    │              ├─ Approve → Publish → Final (Published)
    │              └─ Reject → Final (Not published)
    └─ Reject → Final (Changes not applied)

Example 4: Conditional Approval

yaml
Trigger: Process order

Calculate Total ({{total}})

Condition: If {{total}} > 1000
    ├─ True → User Approval: "Approve {{total}} order?"
    │            ├─ Approve → Process Order → Final
    │            └─ Reject → Final (Order cancelled)
    └─ False → Process Order → Final (Auto-processed)

Using Context Variables

You can use any context variables in your approval message:

Available Variables

javascript
// From trigger
{{input.fieldName}}

// From previous steps
{{stepOutput.value}}

// Current item in loops
{{item.property}}

// Custom variables
{{customVariable}}

Examples

"Approve transfer of {{amount}} {{currency}} to {{recipient}}?"
"Delete {{count}} items?"
"Send email to {{email}} with subject '{{subject}}'?"
"Publish {{title}} to {{platform}}?"
"Grant {{role}} access to {{userName}}?"

API Integration

For Custom Implementations

If you're building a custom UI or integration, you can interact with the approval system via API:

Resume Message Endpoint

http
POST /api/v1/peer/message/:messageId/resume

Request:

json
{
  "decision": "approve"  // or "reject"
}

Response:

json
{
  "success": true,
  "message": {
    "_id": "msg_123",
    "status": "completed",
    "content": "Action completed successfully",
    "approval": {
      "decision": "approve",
      "timestamp": "2025-10-23T00:51:05Z"
    }
  }
}

JavaScript Example

javascript
async function resumeMessage(messageId, decision) {
  const response = await fetch(`/api/v1/peer/message/${messageId}/resume`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ decision })
  });
  
  return response.json();
}

// Usage
await resumeMessage('msg_123', 'approve');

Technical Details

State Management

When a flow pauses for approval:

  1. State Saved: Current execution context is serialized and saved to database
  2. Message Updated: Message status changes to pending_approval
  3. User Notified: Approval UI is displayed
  4. Flow Paused: Execution stops, resources are released

When user responds:

  1. State Loaded: Saved context is retrieved from database
  2. Flow Resumed: Execution continues from the exact point it paused
  3. Decision Applied: Flow branches based on approve/reject
  4. Completion: Remaining steps execute and final result is returned

Performance

  • State Size: Context is efficiently serialized (~5-50KB typical)
  • Resume Time: <500ms from approval click to flow resumption
  • Scalability: Can handle thousands of pending approvals
  • Timeout: No automatic timeout (approval can wait indefinitely)

Best Practices

Message Design

Good Messages:

  • Clear and concise
  • Include relevant context
  • State consequences
  • Use action verbs
"Delete 50 products? This cannot be undone."
"Approve $1,250 payment to Vendor XYZ?"
"Send invoice #12345 to customer@email.com?"

Avoid:

  • Vague messages: "Continue?"
  • Missing context: "Approve?"
  • Too much text: Long paragraphs
  • Technical jargon: "Execute DELETE operation?"

Flow Design

Do:

  • Place approval before critical actions
  • Test both approve and reject paths
  • Provide meaningful final messages
  • Use for genuinely important decisions

Don't:

  • Chain too many approvals (hurts UX)
  • Use for trivial confirmations
  • Forget to handle reject path
  • Block non-critical operations

Error Handling

Always handle potential issues:

yaml
User Approval: "Proceed with action?"
    ├─ Approve → Try Action
    │              ├─ Success → Final (Completed)
    │              └─ Error → Final (Failed: {{error}})
    └─ Reject → Final (Cancelled by user)

Troubleshooting

Approval Not Showing

Possible Causes:

  • Flow hasn't reached approval step yet
  • Frontend not properly integrated
  • WebSocket connection issues

Solutions:

  • Check flow execution logs
  • Verify message status is pending_approval
  • Test WebSocket connectivity

Resume Fails

Possible Causes:

  • Invalid message ID
  • Message already completed
  • State data corrupted

Solutions:

  • Verify message ID is correct
  • Check message status before resuming
  • Review server logs for errors

Flow Doesn't Continue

Possible Causes:

  • Next step not connected properly
  • Error in subsequent step
  • Missing required variables

Solutions:

  • Verify step connections in Flow Editor
  • Check step validation
  • Review execution context

Advanced Use Cases

Approval with Timeout

yaml
User Approval: "Approve within 5 minutes?"
    ├─ Approve → Execute Action
    └─ Reject → Cancel
    
(External timeout mechanism)
After 5 minutes → Auto-reject via API

Approval with Delegation

yaml
User Approval 1: "Manager approval required"
    ├─ Approve → User Approval 2: "Director approval required"
    │              ├─ Approve → Execute
    │              └─ Reject → Cancel
    └─ Reject → Cancel

Approval with Conditions

yaml
Calculate Risk Score

Condition: If {{riskScore}} > 7
    ├─ High Risk → User Approval: "High risk detected!"
    │                 ├─ Approve → Execute with Extra Validation
    │                 └─ Reject → Cancel
    └─ Low Risk → Auto Execute

Summary

User Approval adds a human-in-the-loop capability to your flows:

  • Pause & Resume: Stop execution, wait for user input, continue safely
  • Flexible: Use anywhere in your flow with any context variables
  • Branching: Different paths for approve vs. reject
  • Persistent: State is saved, can wait indefinitely
  • User-Friendly: Clean UI in chat and webchat interfaces

Common Pattern:

Action Preparation → User Approval → Execute if Approved → Final Result

Use User Approval to add safety, compliance, and human oversight to your automated workflows!

Built with VitePress