Skip to content

Decision Steps

Decision steps are the most fundamental workflow component in Aptiwise, requiring human approval with either binary (approve/reject) or multi-outcome decision paths. They form the backbone of most approval processes.

Decision steps pause workflow execution and wait for a designated approver to make a choice. The workflow then continues based on the decision made, allowing for flexible routing and process control.

The most common pattern: approve or reject with different outcomes for each choice.

manager_approval:
name: "Manager Approval"
type: "decision"
description: "Manager reviews and approves request"
approver: "${requestor.manager}"
on_approve:
continue_to: "FinanceReview"
on_reject:
notify_requestor: "Request denied by manager"
end_workflow: true
  • approver: Who makes the decision (role, email, or dynamic reference)
  • on_approve: Action when approved (continue to next step)
  • on_reject: Action when rejected (typically end workflow)
  • timeout: Optional SLA for decision making

For complex scenarios requiring more than simple approve/reject choices:

triage_step:
name: "Triage Support Ticket"
type: "decision"
description: "Classify and route support request"
approver: "support_lead"
# Custom outcome options
on_technical:
text: "Assign to Technical Team"
continue_to: "TechnicalReview"
style: "primary"
on_billing:
text: "Assign to Billing"
continue_to: "BillingReview"
style: "secondary"
on_escalate:
text: "Escalate to Senior Support"
continue_to: "SeniorReview"
style: "warning"
on_close:
text: "Close as Duplicate"
style: "destructive"
notify_requestor: "Ticket closed as duplicate"
end_workflow: true
finance_approval:
name: "Finance Approval"
type: "decision"
approver: "finance_manager" # Specific role
manager_approval:
name: "Manager Approval"
type: "decision"
approver: "${requestor.manager}" # User's direct manager
specialist_review:
name: "Specialist Review"
type: "decision"
approver: "specialist@company.com" # Specific email

For vendors, clients, contractors, or partners who don't have accounts:

vendor_approval:
name: "Vendor Approval"
type: "decision"
approver:
email: "vendor@external.com"
name: "Jane Smith"
position: "Vendor Representative"
employee_type: "external" # Options: internal, external, contractor
approval_type: "needs_to_sign"

Dynamic external approvers from form data:

client_signature:
name: "Client Signature"
type: "decision"
approver:
email: "${form.client_email}"
name: "${form.client_name}"
position: "${form.client_company}"
employee_type: "external"
approval_type: "needs_to_sign"
on_approve:
continue_to: "completion"

Features:

  • Automatically creates employee record if email doesn't exist
  • No pre-registration required
  • Signature captured and stored
  • Future invitations can be sent for full account access

Common use cases:

  • Vendor sign-offs on purchase orders
  • Client acknowledgements on contracts
  • Contractor certifications
  • Partner approvals
department_approval:
name: "Department Approval"
type: "decision"
approver: |
{% if department == 'engineering' %}
cto
{% elif department == 'finance' %}
cfo
{% else %}
department_head
{% endif %}

Different approval behaviors for various scenarios:

signature_required:
name: "Contract Signature"
type: "decision"
approval_type: "needs_to_sign" # Requires digital signature
approver: "legal_counsel"
recommendation_step:
name: "Advisory Review"
type: "decision"
approval_type: "needs_to_recommend" # Cannot block workflow
approver: "advisor"
acknowledgment_step:
name: "FYI Notification"
type: "decision"
approval_type: "needs_to_acknowledge" # Simple acknowledgment
approver: "stakeholder"
primary_approval:
name: "Primary Approval"
type: "decision"
approver: "primary_approver"
backup_approvers:
- "backup_approver_1"
- "backup_approver_2"
delegation_enabled: true
auto_delegate_after: "48_hours"

By default, approval notification emails contain a public token link — the approver can approve or reject directly from the email without logging in. This is ideal for external approvers, vendors, or occasional participants who may not have accounts.

Set require_login: true on any decision step to send an authenticated link instead, requiring the approver to be signed in before acting:

# Default: public token link — no login required
standard_approval:
name: "Standard Approval"
type: "decision"
approver: "${requestor.manager}"
on_approve:
continue_to: "next_step"
# Opt-in: authenticated link — login required
sensitive_approval:
name: "Sensitive Approval"
type: "decision"
approver: "security_officer"
require_login: true
on_approve:
continue_to: "next_step"
on_reject:
end_workflow: true

When to use require_login: true:

  • High-security decisions where you want to enforce authentication before acting
  • Steps subject to MFA or SSO policies
  • Internal approvals where all designated approvers always have accounts

When to use the default (no require_login):

  • External vendors, clients, or contractors approving via email
  • Occasional approvers who may not have a system account yet
  • High-volume workflows where frictionless approval matters
review_with_feedback:
name: "Review with Feedback"
type: "decision"
approver: "reviewer"
require_comments: true # Force comment on rejection
allow_comments: true # Allow optional comments
on_approve:
continue_to: "implementation"
on_request_changes:
text: "Request Changes"
continue_to: "revision"
require_comments: true
on_reject:
end_workflow: true
workflow:
# Step 1: Manager approval for all purchases
manager_approval:
name: "Manager Approval"
type: "decision"
approver: "${requestor.manager}"
on_approve:
continue_to: "amount_check"
on_reject:
notify_requestor: "Purchase request denied by manager"
end_workflow: true
# Step 2: Additional approvals based on amount
amount_check:
name: "Amount-based routing"
type: "conditional_split"
choices:
- conditions: "amount > 10000"
continue_to: "director_approval"
default:
continue_to: "procurement"
# Step 3: Director approval for high-value items
director_approval:
name: "Director Approval"
type: "decision"
approver: "${requestor.department_head}"
on_approve:
continue_to: "procurement"
on_reject:
notify_requestor: "High-value purchase denied by director"
end_workflow: true
leave_approval:
name: "Leave Request Approval"
type: "decision"
approver: "${requestor.manager}"
on_approve:
text: "Approve Leave"
continue_to: "hr_notification"
on_approve_partial:
text: "Approve with Modifications"
continue_to: "modification_review"
require_comments: true
on_reject:
text: "Deny Leave Request"
notify_requestor: "Leave request denied"
require_comments: true
end_workflow: true
  1. Clear Outcomes: Each decision path should have a clear, unambiguous purpose
  2. Meaningful Labels: Use descriptive text for custom outcome buttons
  3. Appropriate Styles: Use visual cues (colors) to indicate action severity
  4. Required Comments: Force explanations for rejections or complex decisions
  1. Timeout Settings: Set realistic SLAs for decision making
  2. Escalation Paths: Define backup approvers and delegation rules
  3. Notification Strategy: Balance urgency with notification fatigue
  4. Audit Trail: Ensure all decisions are properly logged
  1. Mobile-Friendly: Ensure decision interfaces work on all devices
  2. Context Awareness: Provide sufficient information for informed decisions
  3. Batch Processing: Allow approvers to handle multiple similar requests efficiently
  4. Preview Mode: Let approvers see the full request before deciding

Next Steps: