Approval Steps
Pause workflows for human approval or input
Approval Steps
Approval steps enable human-in-the-loop (HITL) workflows by pausing execution until a designated approver takes action. Use them for scenarios requiring human judgment, data entry, or authorization before proceeding.
Configuration
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique step identifier |
type | string | Yes | Must be "approval" |
name | string | Yes | Human-readable name |
config.approvers | string[] | Yes | List of approver identifiers (email, user ID, or template) |
config.reason | string | Yes | Reason shown to approvers explaining what needs approval |
config.timeoutMs | number | No | Timeout in milliseconds (default: 86400000 / 24 hours) |
config.notifyChannels | object | No | Channels to send approval notifications |
Notification Channels
Configure where approval requests are sent:
| Field | Type | Description |
|---|---|---|
slack | string | Slack channel ID or name for notifications |
slackThreadTs | string | Thread timestamp to reply in (for threaded conversations) |
email | boolean | Whether to send email notifications |
Slack Threading
Use slackThreadTs to post approval requests as thread replies, keeping conversations organized:
Input Types
Control how approvers interact with the approval request:
| Field | Type | Default | Description |
|---|---|---|---|
inputType | string | "buttons" | Input type: "buttons", "text", or "both" |
inputLabel | string | - | Label for text input field |
inputPlaceholder | string | - | Placeholder text for text input |
approveLabel | string | "Approve" | Custom label for approve/submit button |
rejectLabel | string | "Reject" | Custom label for reject/cancel button |
Button Mode (Default)
Standard approve/reject buttons:
Text Input Mode
Collect text input from approvers via a modal:
When inputType is "text", clicking the approve button opens a Slack modal for text entry. The entered value is available in the step output.
Both Mode
Show both approve/reject buttons and a text input option:
Output
Approval steps return information about the decision:
| Field | Description |
|---|---|
decision.approved | Whether the request was approved (true) or rejected (false) |
decision.approvedBy | Identifier of the user who made the decision |
decision.approvedAt | ISO 8601 timestamp of the decision |
decision.reason | Text input provided by the approver (if inputType includes text) |
Common Patterns
Amount-Based Approval Routing
Route to different approvers based on amount:
Sequential Multi-Level Approval
Require approval from multiple levels:
Data Collection in Loops
Collect user input across multiple iterations:
Slack-Triggered Approval with Threading
Handle approvals from Slack conversations:
Timeout Handling
When an approval times out:
- The step completes with a timeout status
- The workflow can handle this in subsequent condition steps
Best Practices
Clear Approval Reasons
Provide context so approvers can make informed decisions:
Appropriate Timeouts
Set timeouts based on urgency:
| Scenario | Timeout | Milliseconds |
|---|---|---|
| Urgent approval | 1 hour | 3600000 |
| Same-day approval | 8 hours | 28800000 |
| Standard approval | 24 hours | 86400000 |
| Extended review | 72 hours | 259200000 |
Thread Continuity
For Slack-triggered workflows, maintain thread context:
Troubleshooting
Approval Not Received
- Check approvers list - Ensure at least one valid approver is specified
- Verify channel access - Bot must have access to notification channels
- Check timeout - Approval may have expired
Slack Modal Not Opening
- Verify inputType - Must be
"text"or"both"for modal - Check connection - Slack connection must be valid
- Ensure bot permissions - Bot needs appropriate scopes
Loop Iterations Not Waiting
Each iteration within a loop creates its own approval waitpoint. Ensure:
- Loop
concurrencyis set to1for sequential processing - Each iteration waits for user response before continuing