Approval Workflows
Set up multi-party approval workflows with human-in-the-loop decision making
Approval Workflows
Need a human to approve something before your workflow continues? The Approval Node pauses your workflow, asks for approval, and then continues based on the decision.
Status: Production-Ready ✅ Version: 1.0 Last Updated: November 2025
How It Works
Approval workflows have two paths:
Your Workflow
↓
┌─────────────────────┐
│ Approval Node │
│ (pause execution) │
└─────────────────────┘
↙ ↘
✅ Approved ❌ Rejected
↓ ↓
Continue Path Reject Path
When the Approval Node runs:
- It pauses the workflow
- It sends a notification (email, Slack, UI)
- An approver responds (approve or reject)
- The workflow resumes on the appropriate path
Tip: Perfect for expense approvals, content review, deployment gates, or any process that needs human sign-off.
Quick Example: Expense Approval
Let's say you want to approve expenses over $1000:
Workflow:
- User submits expense form (trigger)
- Check if amount > $1000
- If yes → Approval Node (pause and wait)
- Manager approves → Send confirmation email
- Manager rejects → Send rejection notice
Approval Node Configuration:
prompt: "Approve expense of ${{ $trigger.amount }} for {{ $trigger.description }}?"
approverId: "{{ $trigger.managerId }}"
requireComment: true
expiresIn: 86400 # 24 hours
Approval Strategies
When you have multiple approvers, how do you make the final decision?
1. ANY — First One Wins
Behavior: First person to approve OR reject decides.
Example:
approvers: ["alice@company.com", "bob@company.com", "charlie@company.com"]
approvalStrategy: "any"
- Alice approves → Approved (Bob and Charlie don't need to respond)
- OR Alice rejects → Rejected (can't override)
Use when: You need quick decisions and don't need consensus.
2. ALL — Everyone Must Agree
Behavior: All approvers must approve. One rejection = rejected.
Example:
approvers: ["alice@company.com", "bob@company.com"]
approvalStrategy: "all"
- Alice approves, Bob approves → Approved
- Alice approves, Bob rejects → Rejected
Use when: Security-critical or all perspectives matter (e.g., security + compliance)
3. MAJORITY — More Than Half
Behavior: More than 50% must approve.
Example:
approvers: ["alice@company.com", "bob@company.com", "charlie@company.com"]
approvalStrategy: "majority"
- 2 approve, 1 rejects → Approved (2/3 > 50%)
- 1 approves, 2 reject → Rejected
Use when: You want input from multiple people but don't need unanimity.
4. WEIGHTED — Custom Weights
Behavior: Each approver has a weight. If total weight meets threshold, approved.
Example:
approvers: ["alice@company.com", "bob@company.com", "charlie@company.com"]
approverWeights:
alice@company.com: 3.0 # CEO
bob@company.com: 2.0 # CFO
charlie@company.com: 1.0 # Manager
approvalStrategy: "weighted"
requiredWeightThreshold: 3.0
- Alice (CEO, weight=3.0) approves → Approved (3.0 ≥ 3.0)
- Bob (CFO, weight=2.0) + Charlie (Manager, weight=1.0) approve → Approved (3.0 ≥ 3.0)
- Only Charlie approves → Rejected (1.0 < 3.0)
Use when: Approvers have different authority levels.
Configuration
Minimal Setup
prompt: "Approve this request?"
approverId: "user@company.com"
That's enough to get started!
Full Configuration
# Basic
prompt: "Approve expense of ${{ $trigger.amount }}?"
approverId: "{{ $workflow.settings.managerId }}"
# Notifications
approvalType: "email" # email, slack, teams, webhook, or ui
requireComment: true
# Timeout
timeoutMinutes: 1440 # 24 hours
# Multi-party approvals
approvers: ["alice@company.com", "bob@company.com"]
approvalStrategy: "majority" # any, all, majority, weighted
# Data to show approver
data:
amount: "{{ $trigger.amount }}"
description: "{{ $trigger.description }}"
requester: "{{ $node['Get User'].json.name }}"
Real-World Examples
Example 1: Expense Approval
Approval Node:
prompt: "Approve ${{ $trigger.amount }} expense?"
approverId: "{{ $trigger.managerId }}"
requireComment: true
timeoutMinutes: 1440
Connections:
approved → Send Approval Email
rejected → Send Rejection Email
Example 2: Content Review
Approval Node:
prompt: "Review and approve blog post: {{ $node['Draft'].json.title }}"
approvers:
- "editor@company.com"
- "manager@company.com"
approvalStrategy: "all" # Both must approve
data:
content: "{{ $node['Draft'].json.content }}"
Example 3: Deployment Gate
Approval Node:
prompt: "Approve deployment to {{ $trigger.environment }}?"
approvers:
- "devops-lead@company.com"
- "security-lead@company.com"
approvalStrategy: "weighted"
approverWeights:
devops-lead@company.com: 2
security-lead@company.com: 2
requiredWeightThreshold: 3 # Both must approve
Output Ports
The Approval Node has two output ports:
- approved — Triggers when the request is approved
- rejected — Triggers when the request is rejected
Connect different workflows to each port:
Approval Node
├─→ approved port → Send Success Email → Update Database
└─→ rejected port → Send Rejection Email → Log Request
Common Mistakes & How to Avoid Them
Mistake 1: Hardcoding approver IDs
❌ Wrong:
approverId: "alice@company.com" # Always asks Alice
✅ Correct:
approverId: "{{ $trigger.managerId }}" # Dynamic based on trigger
Mistake 2: Forgetting expiration
❌ Wrong:
# No timeout - approval request never expires!
✅ Correct:
timeoutMinutes: 1440 # 24 hours
Mistake 3: Wrong strategy for the use case
❌ Wrong:
# Security approval needs both security AND compliance
approvalStrategy: "any" # Oops, only one person needs to approve
✅ Correct:
approvalStrategy: "all" # Both must approve
Best Practices
- ✅ Use expressions for dynamic approvers — Assign approval to the right person based on data
- ✅ Always set timeout — Prevent approvals from hanging forever
- ✅ Include context in data — Show approvers what they're reviewing
- ✅ Use weighted for hierarchies — CEO's approval might be more important
- ✅ Test approval flow — Verify the approved and rejected paths work
- ❌ Don't hardcode approvers — Use expressions for flexibility
- ❌ Don't skip requireComment — Comments help with audit trails
- ❌ Don't use "any" for critical approvals — Use "all" or "weighted" instead
Next Steps
- Build your first workflow — Add an approval node to a simple workflow
- Test approval paths — Verify both approved and rejected routes
- Set up notifications — Configure email or Slack to notify approvers
- Use multi-party approval — Try "majority" or "weighted" strategies
- Integrate with your data — Use expressions to pass context to approvers
Related:
- Expressions Guide — Use
{{ }}for dynamic approvers - Error Recovery — Handle timeout scenarios
- AI Agent Node — Use AI to draft content for approval