Configure Approvals Engine
Detail regarding configuration information for Moveworks Native Approvals Engine
What is Approval Engine?
Approvals Engine is a platform that orchestrates approvals, built into the Moveworks platform. These are workflows designed to automate the approval process for tasks and functions within a system.
Approvals Engine provides a sequence of validations for different actions or requests, such as permissions to a resource or additions to a distribution list. These processes can be tailored according to specific roles, tasks, and predefined conditions.
Key Use Cases:
By employing conditions and rules, these approval workflows filter and sort requests to eliminate unnecessary steps and find the most efficient path to resolution.
Overview
Approval workflows control who needs to approve software access requests, group memberships, and other privileged actions before they're granted. Moveworks provides pre-built approval workflows for common scenarios, and allows you to create custom workflows for complex requirements.
The Goal: Get the right approvals from the right people, automatically, without slowing down users or creating unnecessary bottlenecks.
Quick Navigation
- How Approval Workflows Work
- Choosing an Approval Workflow
- Built-In Approval Workflows
- Custom Approval Workflows
- Common Use Cases
How Approval Workflows Work
The Approval Flow
- User requests access (e.g., "I need Salesforce access")
- Moveworks evaluates the approval workflow configured for that resource
- Approval requests sent to the appropriate people based on the workflow
- Approvers receive notification in their chat platform (Slack, Teams, etc.)
- Approvers approve or deny with one click
- Access is granted automatically if approved (or denied if rejected)
Who Can Be an Approver?
- Manager - The requester's direct manager
- App Admin - Designated administrators for specific applications
- Group Owner - Owners of distribution lists or security groups
- Specific Users - Named individuals (e.g., Security team lead)
- Group Members - Any member of a designated approval group
- Automatic - No approval needed (auto-approve) or auto-deny
Choosing an Approval Workflow
Decision Guide
Ask yourself these questions:
1. How sensitive is this resource?
- Low risk (e.g., Slack, Zoom Basic) → Auto-approve or Manager approval
- Medium risk (e.g., Salesforce, internal tools) → Manager or App Admin
- High risk (e.g., production systems, financial tools) → Sequential approvals (Manager + App Admin)
2. Who knows if this person should have access?
- Their manager knows → Manager approval
- IT/App owner knows → App Admin approval
- Both should agree → Sequential approval (Manager then App Admin)
- No one needs to decide → Auto-approve
3. Are there special cases?
- Different rules for contractors? → Conditional approval based on employee type
- Different rules by department? → Conditional approval based on department
- Different rules by role level? → Role-based approval
Built-In Approval Workflows
These are pre-configured workflows ready to use immediately.
🟢 Self-Service
| Workflow | Who Approves | When to Use | Example Use Case |
|---|---|---|---|
| AUTO_APPROVE | No one (automatic) | Low-risk software everyone should have access to | Slack, Zoom Basic, company wiki |
| AUTO_APPROVE_FULL_TIME_ELSE_MANAGER | Auto for employees, Manager for contractors | Standard tools but contractors need review | Microsoft Office, standard SaaS tools |
| AUTO_APPROVE_FULL_TIME_ELSE_APP_ADMIN | Auto for employees, App Admin for contractors | IT-managed tools, contractors need special setup | VPN access, dev tools |
Example scenario:
"Everyone should have Slack, so we use AUTO_APPROVE. For VPN though, employees get it automatically but contractors need IT approval, so we use AUTO_APPROVE_FULL_TIME_ELSE_APP_ADMIN."
🟡 Standard Approval
| Workflow | Who Approves | When to Use | Example Use Case |
|---|---|---|---|
| MANAGER | User's direct manager | Manager knows if user needs this for their job | Salesforce, Jira, specialized tools |
| APP_ADMIN | Application administrators | IT/app owner needs to provision or has technical knowledge | Admin panels, specialized software |
Example scenario:
"For Salesforce, managers know who on their team needs it, so we use MANAGER approval. For our internal admin tool, IT needs to set up accounts, so we use APP_ADMIN approval."
🔴 Multi-Level Approval
| Workflow | Who Approves | When to Use | Example Use Case |
|---|---|---|---|
| APP_ADMIN_THEN_MANAGER | App Admin first, then Manager | Both IT and manager need to agree, IT checks first | Production access, elevated permissions |
| MANAGER_THEN_DL_OWNER | Manager first, then Group Owner | Adding to sensitive groups | Executive mailing lists, privileged groups |
Example scenario:
"For production database access, IT (APP_ADMIN) confirms the person is technically qualified, then their manager confirms they need it for their role."
🔵 Group-Specific Workflows (Trust Models)
These workflows apply to distribution lists and group memberships. They use "trust models" that make approval decisions based on the group's configuration in your identity system (Okta, Azure AD, Google Workspace, etc.).
Understanding Trust Models
Trust models check the group's settings to determine if approval is needed:
Key Group Properties:
- Access Type/Join Policy: How users can join (Open, Owner Approval Required, Closed, etc.)
- Self-Managed: Whether the group allows self-service membership
- Visibility: Public vs Private groups
- Owner Settings: Whether owner approval is required
STANDARD_TRUST_MODEL
Who Approves: Automatic if group allows self-service, else Group Owner
Conditions for Auto-Approval:
- Group is marked as "self-managed" OR
- Group access type is "Open" or "Anyone can join" OR
- Group explicitly allows members to add themselves
Otherwise: Group Owner must approve
When to Use:
- Standard distribution lists
- Team mailing lists
- Department groups with normal security requirements
Example:
"For team distribution lists, if the group is configured as 'open' in Azure AD, anyone can join automatically. If it requires owner approval, the group owner must approve."
MOST_RESTRICTIVE_TRUST_MODEL
Who Approves: Group Owner unless very specific auto-approval conditions are met
Conditions for Auto-Approval (ALL must be true):
- Requester is already a member of a parent group OR
- Group explicitly allows self-service membership AND
- Group is public/visible AND
- Group access type is "Open" or "Anyone can join"
Otherwise: Group Owner must approve
When to Use:
- Executive distribution lists
- Sensitive information groups
- Compliance-required groups
- Security team lists
Example:
"For the Executive Team mailing list, the group owner must approve every request, even if someone's manager requests access for them. Only if the group is explicitly configured as 'open' and 'self-service' would it auto-approve."
Why "Most Restrictive":
- Requires Group Owner approval by default
- Only auto-approves when multiple conditions align
- Protects sensitive groups from accidental access
- Ensures conscious approval decisions
LEAST_RESTRICTIVE_TRUST_MODEL
Who Approves: Automatic for most groups, Group Owner only for explicitly restricted groups
Conditions for Auto-Approval:
- Group is NOT marked as "Closed" or "Private" AND
- Group does NOT explicitly require owner approval for all joins
Otherwise: Group Owner must approve
When to Use:
- All-company announcements
- Public distribution lists
- Open collaboration groups
- Social/interest groups
Example:
"For the 'All Company' mailing list, anyone can join automatically unless the group is specifically configured as closed or private."
Trust Model Variants with Fallbacks
Some trust models have "fallback" options that change the approval behavior when conditions aren't met:
| Workflow | Approval Logic | Use Case |
|---|---|---|
| STANDARD_WITH_FALLBACK_TO_MANAGER | Standard trust check, but if Group Owner approval needed and owner is unavailable → Manager approves | Groups where manager can substitute for owner |
| MOST_RESTRICTIVE_WITH_FALLBACK_TO_MANAGER | Most restrictive check, but Manager can approve if Group Owner unavailable | Sensitive groups with manager backup |
| MANAGER_THEN_DL_OWNER | Manager approves first, then Group Owner (sequential) | Dual approval for sensitive groups |
| MANAGER_THEN_DL_OWNER_WITH_FALLBACK_TO_AUTO_APPROVE | Manager then Group Owner, but auto-approve if both unavailable | Flexible group access with backup |
Google Workspace Specific
| Workflow | Who Approves | When to Use |
|---|---|---|
| GSUITE_OPEN_OR_OWNER | Auto if Google group is "Open", else Group Owner | Google Workspace groups |
Google-Specific Conditions:
- Checks Google Groups "Who can join" setting
- "Anyone can join" → Auto-approve
- "Invited users" or "Can request" → Group Owner approves
Choosing the Right Trust Model
Use LEAST_RESTRICTIVE when:
- Group should be easily accessible
- Low-security concern
- Broad collaboration needed
- Example: [email protected]
Use STANDARD when:
- Normal security requirements
- Want to respect group's self-service settings
- Balance between access and control
- Example: [email protected]
Use MOST_RESTRICTIVE when:
- Sensitive information shared
- Compliance requirements
- Executive or leadership groups
- Want explicit approval for every request
- Example: [email protected], [email protected]
Example scenario:
"For our all-company mailing list, anyone can join (LEAST_RESTRICTIVE). For our executive team list, the group owner must approve everyone (MOST_RESTRICTIVE). For department teams, we trust the group's configuration (STANDARD)."
📋 Complete Built-In Workflows Reference
| Workflow Name | Approval Flow | Best For |
|---|---|---|
| AUTO_APPROVE | Automatic approval | Low-risk, widely available software |
| MANAGER | Direct manager approves | Standard business applications |
| APP_ADMIN | App administrators approve | IT-managed or specialized tools |
| APP_ADMIN_THEN_MANAGER | App admin → Manager (sequential) | High-risk software, dual approval needed |
| AUTO_APPROVE_FULL_TIME_ELSE_MANAGER | Auto for FTE, Manager for contractors | Standard tools with contractor restrictions |
| AUTO_APPROVE_FULL_TIME_ELSE_APP_ADMIN | Auto for FTE, App Admin for contractors | IT tools with contractor restrictions |
| STANDARD_TRUST_MODEL | Conditional auto-approve or Group Owner | Standard distribution lists |
| STANDARD_WITH_FALLBACK_TO_MANAGER | Conditional auto-approve or Manager | Distribution lists, manager fallback |
| MOST_RESTRICTIVE_TRUST_MODEL | Strict conditions or Group Owner | Sensitive distribution lists |
| MOST_RESTRICTIVE_WITH_FALLBACK_TO_MANAGER | Strict conditions or Manager | Sensitive groups, manager fallback |
| MOST_RESTRICTIVE_WITH_FALLBACK_TO_DL_MANAGER | Strict conditions → DL Manager | Sensitive groups, DL manager fallback |
| LEAST_RESTRICTIVE_TRUST_MODEL | Flexible auto-approve or Group Owner | Open/public distribution lists |
| MANAGER_THEN_DL_OWNER | Manager → Group Owner (sequential) | Sensitive groups, dual approval |
| MANAGER_THEN_DL_OWNER_WITH_FALLBACK_TO_AUTO_APPROVE | Manager → Group Owner, or auto | Flexible group access |
| GSUITE_OPEN_OR_OWNER | Auto if open, else Group Owner | Google Workspace groups |
| ADD_TO_DL_APPROVAL | Most restrictive → Manager fallback | Adding users to distribution lists |
| REMOVE_FROM_DL_APPROVAL | Most restrictive → Manager fallback | Removing users from distribution lists |
| CREATE_DL_APPROVAL | Automatic approval | Creating new distribution lists |
| GET_DL_MANAGER_APPROVAL | Distribution List Manager | DL management operations |
Custom Approval Workflows
When built-in workflows don't fit your needs, create custom workflows.
When to Create Custom Workflows
- Complex approval chains (e.g., Manager → VP → Security team)
- Conditional approvals based on user attributes (department, seniority, location)
- Role-specific approvals (different approvers for different software roles)
- Approval groups (any 2 of 5 people can approve)
- Special business rules (e.g., "sales VPs can approve any sales tool request")
Custom Workflow Types
1. Sequential Approval (One After Another)
Approvals happen in order. Second approver only notified after first approves.
When to use:
- Manager needs to approve before IT sets up the account
- Multiple levels of approval needed (Manager → Director → VP)
- Progressive escalation
Example: Manager then App Admin
{
"sequential_expression": {
"expressions": [
{
"manager_expression": {}
},
{
"app_admin_expression": {}
}
]
}
}User Experience:
- Manager gets approval request
- Manager approves
- Then App Admin gets approval request
- App Admin approves
- Access is granted
2. Parallel Approval (Multiple People at Once)
All approvers notified at the same time. Can require all to approve or just some.
When to use:
- Any one of several people can approve (1 of 3 required)
- All approvers must agree (3 of 3 required)
- Faster than sequential when order doesn't matter
Example: Any 1 of 3 VPs can approve
{
"parallel_expression": {
"expressions": [
{
"user_constant_expression": {
"user": "[email protected]"
}
},
{
"user_constant_expression": {
"user": "[email protected]"
}
},
{
"user_constant_expression": {
"user": "[email protected]"
}
}
],
"number_required": 1
}
}User Experience:
- All 3 VPs get approval request simultaneously
- First VP to approve completes the approval
- Other VPs' requests are auto-dismissed
- Access is granted
3. Conditional Approval (Based on User Attributes)
Different approval paths based on who is requesting or what they're requesting.
When to use:
- Different rules for employees vs contractors
- Different approvers by department
- Different approvers by seniority level
- Role-based approval flows
Example: Auto-approve for senior staff, Manager approval for others
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "users_requested_for[0].custom_attributes.seniority_level IN [\"Director\", \"VP\", \"SVP\", \"EVP\"]"
},
"expression": {
"auto_approve_expression": {}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}User Experience:
- Directors and above: Access auto-approved
- Everyone else: Manager must approve
4. Approval Group (Any Member of a Group)
Send approval to everyone in a specific group. Can require 1 or more to approve.
When to use:
- Approval from "Security Team" (any member can approve)
- IT helpdesk approval (any available admin)
- On-call rotation (whoever is available)
- Distributed approval responsibility
How It Works:
- Define a group in your identity system (Okta, Azure AD, etc.) containing all potential approvers
- Configure how many group members must approve (
number_required) - All group members receive the approval request simultaneously
- Once the required number approve, access is granted
- Remaining approval requests are auto-dismissed
Key Parameters:
| Parameter | Description | Example Values |
|---|---|---|
external_id | The group ID from your identity system | 00gq0p1j6jGsb0ZCO2p8 (Okta), sg-12345678 (AWS), [email protected] (Google) |
integration_id | Your identity system integration ID | okta, azure_ad, google_workspace |
number_required | How many members must approve | 1 (any one), 2 (any two), 3 (any three) |
role | Which group role can approve | MEMBER (any member), OWNER (only owners) |
Example: Any 2 members of IT Security team must approve
{
"parallel_group_expression": {
"group": {
"external_id": "00gq0p1j6jGsb0ZCO2p8",
"integration_id": "okta"
},
"number_required": 2,
"role": "MEMBER"
}
}User Experience:
- User requests production database access
- All 8 IT Security team members get approval request in Slack/Teams
- First 2 team members to approve complete the requirement
- Other 6 team members' requests are auto-dismissed
- Access is granted automatically
Finding Your Group's external_id:
Different systems use different formats:
Okta:
- Navigate to: Directory → Groups → [Select Group]
- Look for "Group ID" in the group details
- Format:
00gABCDEF123456789
Azure AD:
- Navigate to: Azure Active Directory → Groups → [Select Group]
- Look for "Object ID"
- Format:
12345678-1234-1234-1234-123456789012
Google Workspace:
- Navigate to: Admin Console → Groups → [Select Group]
- Look for "Group Email"
- Format:
[email protected]
Getting Your integration_id:
- Contact Moveworks Support with your identity system name
- They will provide the correct
integration_idfor your org - This is typically your connector name in Moveworks Setup
Note: Approval groups are powerful for distributed approval responsibility but require proper group management in your identity system.
5. Role-Based Conditional Approval
Different approvers based on which role/license level is selected.
When to use:
- Different approvers for Basic vs Pro vs Enterprise
- Different approval for read-only vs admin access
- Elevated permissions need higher approval
Example: Basic role auto-approved, Admin role needs VP approval
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "approval_request.approvable_entity.app_entity.role_canonical_name_to_provision.$LOWERCASE() == \"basic_user\".$LOWERCASE()"
},
"expression": {
"manager_expression": {}
}
},
{
"condition": {
"rule_v2": "approval_request.approvable_entity.app_entity.role_canonical_name_to_provision.$LOWERCASE() == \"admin\".$LOWERCASE()"
},
"expression": {
"sequential_expression": {
"expressions": [
{
"manager_expression": {}
},
{
"user_constant_expression": {
"user": "[email protected]"
}
}
]
}
}
}
],
"default_expression": {
"auto_deny_expression": {}
}
}
}User Experience:
- User requests Basic role → Manager approves
- User requests Admin role → Manager approves, then VP must approve
- User requests any other role → Auto-denied
Creating a Custom Workflow
Step 1: Navigate to Native Approvals
Path: Moveworks Setup → Access Management → Moveworks Native Approvals
Step 2: Click "Create"
Start a new custom approval workflow.
Step 3: Name Your Workflow
Use a descriptive name that explains what it does:
✅ Good names:
Manager_Then_IT_Security_TeamSales_VP_Approval_For_CRM_ToolsDirector_Plus_Auto_Approve
❌ Bad names:
Custom_Approval_1New_FlowTest
Step 4: Build Your Workflow Expression
Use the JSON format documented below. Start simple and test before adding complexity.
Step 5: Save and Test
Save your workflow, then assign it to a test application and try requesting access.
Step 6: Assign to Software/Groups
Navigate to the software or group configuration and select "Custom Approval Workflow" under Provisioning Method.
Common Use Cases
Use Case 1: Software with Free and Paid Tiers
Scenario: Zoom has Basic (free) and Pro (paid) licenses. Basic auto-approved, Pro needs manager approval.
Solution: Role-based conditional approval
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "approval_request.approvable_entity.app_entity.role_canonical_name_to_provision.$LOWERCASE() == \"zoom_basic\".$LOWERCASE()"
},
"expression": {
"auto_approve_expression": {}
}
},
{
"condition": {
"rule_v2": "approval_request.approvable_entity.app_entity.role_canonical_name_to_provision.$LOWERCASE() == \"zoom_pro\".$LOWERCASE()"
},
"expression": {
"manager_expression": {}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}Use Case 2: Contractor Restrictions
Scenario: Employees get software automatically, contractors need manager approval for security review.
Solution: Use built-in AUTO_APPROVE_FULL_TIME_ELSE_MANAGER
Or create custom based on employment type:
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "users_requested_for[0].is_full_time_employee == true"
},
"expression": {
"auto_approve_expression": {}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}Use Case 3: Department-Specific Approvers
Scenario: Sales tools approved by Sales VP, Engineering tools approved by CTO.
Solution: Conditional approval by department
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "users_requested_for[0].department.$LOWERCASE() == \"sales\".$LOWERCASE()"
},
"expression": {
"user_constant_expression": {
"user": "[email protected]"
}
}
},
{
"condition": {
"rule_v2": "users_requested_for[0].department.$LOWERCASE() == \"engineering\".$LOWERCASE()"
},
"expression": {
"user_constant_expression": {
"user": "[email protected]"
}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}Use Case 4: Tiered Approval Based on Seniority
Scenario: Directors and above auto-approved, everyone else needs manager approval.
Solution: Conditional approval by seniority
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "users_requested_for[0].custom_attributes.seniority_level IN [\"Director\", \"VP\", \"SVP\", \"C-Level\"]"
},
"expression": {
"auto_approve_expression": {}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}Note: Requires seniority_level as a custom user attribute. See User Identity for available attributes.
Use Case 5: Approval from Any IT Admin
Scenario: IT admin approval needed, but any IT admin can approve (not specific person).
Solution: Approval group
{
"parallel_group_expression": {
"group": {
"external_id": "00gIT8AdminGroup",
"integration_id": "okta"
},
"number_required": 1,
"role": "MEMBER"
}
}Contact Moveworks Support to get your integration_id for the identity system containing your approval group.
Use Case 6: Requesting Access for Someone Else
Scenario: Manager requests software for a team member - should auto-approve if manager is requesting for their direct report.
Solution: Conditional approval checking relationship
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "users_requested_for[0].manager_email == requestor.email_addr"
},
"expression": {
"auto_approve_expression": {}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}Approval Expression Reference
Basic Expressions
Auto-Approve
{
"auto_approve_expression": {}
}Auto-Deny
{
"auto_deny_expression": {}
}Specific User
{
"user_constant_expression": {
"user": "[email protected]"
}
}Manager
{
"manager_expression": {}
}App Admin
{
"app_admin_expression": {}
}Reference Another Workflow
{
"referenced_expression": {
"name": "Name_Of_Other_Workflow"
}
}Combining Expressions
Sequential (one after another)
{
"sequential_expression": {
"expressions": [
{ "manager_expression": {} },
{ "app_admin_expression": {} }
]
}
}Parallel (all at once, N required)
{
"parallel_expression": {
"expressions": [
{ "user_constant_expression": { "user": "[email protected]" } },
{ "user_constant_expression": { "user": "[email protected]" } }
],
"number_required": 1
}
}Conditional (if/else logic)
{
"condition_expression": {
"clauses": [
{
"condition": {
"rule_v2": "CONDITION_HERE"
},
"expression": {
"auto_approve_expression": {}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}Approval Group
{
"parallel_group_expression": {
"group": {
"external_id": "GROUP_ID_HERE",
"integration_id": "INTEGRATION_ID_HERE"
},
"number_required": 1,
"role": "MEMBER"
}
}Available User Attributes for Conditions
Use these in rule_v2 conditions:
Standard User Attributes
| Attribute | Example Value | Use Case |
|---|---|---|
requestor.email_addr | [email protected] | Check who is requesting |
users_requested_for[0].email_addr | [email protected] | Check who access is for |
users_requested_for[0].department | Engineering | Department-based rules |
users_requested_for[0].role | Software Engineer | Role-based rules |
users_requested_for[0].manager_email | [email protected] | Manager relationship checks |
users_requested_for[0].is_full_time_employee | true | Employee type checks |
users_requested_for[0].work_status | FULL_TIME | Work status checks |
users_requested_for[0].location | San Francisco | Location-based rules |
Custom Attributes
| Attribute | Example | Use Case |
|---|---|---|
users_requested_for[0].custom_attributes.seniority_level | Director | Seniority-based approval |
users_requested_for[0].custom_attributes.cost_center | 8000 | Budget approval routing |
users_requested_for[0].custom_attributes.clearance_level | Secret | Security clearance checks |
See available attributes: User Identity Module
Request Attributes
| Attribute | Example | Use Case |
|---|---|---|
approval_request.approvable_entity.app_entity.role_canonical_name_to_provision | admin_role | Role-based approval |
approval_request.approvable_entity.app_entity.name | Salesforce | App-specific rules |
Condition Syntax Examples
Conditions in rule_v2 use the Moveworks DSL (Domain-Specific Language) for evaluating user attributes and request context.
Basic Syntax Rules
Accessing Values:
- Use dot notation:
object.field - Array access:
array[index] - First item in array:
users_requested_for[0]
Comparison Operators:
- Equal:
== - Not equal:
!= - Greater than:
> - Less than:
< - In list:
IN
Functions:
$LOWERCASE()- Convert to lowercase for case-insensitive comparison$UPPERCASE()- Convert to uppercase
String Comparison (Case-Insensitive)
Why use $LOWERCASE():
- User data may have inconsistent casing ("Sales", "sales", "SALES")
- Always use for reliable string matching
// Check if user is in Sales department
users_requested_for[0].department.$LOWERCASE() == "sales".$LOWERCASE()
// Check user's role
users_requested_for[0].role.$LOWERCASE() == "software engineer".$LOWERCASE()
// Check location
users_requested_for[0].location.$LOWERCASE() == "san francisco".$LOWERCASE()List Membership
Check if a value is in a list of allowed values:
// Check if seniority level is senior
users_requested_for[0].custom_attributes.seniority_level IN ["Director", "VP", "SVP", "C-Level"]
// Check if department is technical
users_requested_for[0].department IN ["Engineering", "IT", "DevOps", "Data Science"]
// Check if work status qualifies
users_requested_for[0].work_status IN ["FULL_TIME", "PART_TIME"]Note: List values are case-sensitive unless you use $LOWERCASE():
// Case-insensitive list check (NOT SUPPORTED directly)
// Instead, normalize the value first:
users_requested_for[0].department.$LOWERCASE() IN ["engineering", "it", "devops"]Boolean Checks
Check true/false values:
// Check if full-time employee
users_requested_for[0].is_full_time_employee == true
// Check if NOT a contractor
users_requested_for[0].is_full_time_employee != false
// Check if user is active
users_requested_for[0].is_active == trueEmail Comparisons
// Check specific email
requestor.email_addr.$LOWERCASE() == "[email protected]".$LOWERCASE()
// Check email domain
requestor.email_addr.$LOWERCASE().$CONTAINS("@company.com")
// Check if requesting for self
users_requested_for[0].email_addr == requestor.email_addrRelationship Checks
// Manager requesting for their direct report
users_requested_for[0].manager_email == requestor.email_addr
// User requesting for themselves
users_requested_for[0].email_addr == requestor.email_addr
// Check if requestor is in user's reporting chain
// (Requires custom attribute tracking reporting chain)
requestor.email_addr IN users_requested_for[0].custom_attributes.reporting_chainRole-Based Checks
// Check the role being requested
approval_request.approvable_entity.app_entity.role_canonical_name_to_provision.$LOWERCASE() == "basic_user".$LOWERCASE()
// Check if requesting admin access
approval_request.approvable_entity.app_entity.role_canonical_name_to_provision.$LOWERCASE() == "admin".$LOWERCASE()
// Check if requesting elevated permissions
approval_request.approvable_entity.app_entity.role_canonical_name_to_provision IN ["admin", "super_admin", "owner"]Combining Conditions with AND
Use nested condition expressions for AND logic:
{
"condition_expression": {
"clauses": [
{
"condition": {
// First condition: Department is Engineering
"rule_v2": "users_requested_for[0].department.$LOWERCASE() == \"engineering\".$LOWERCASE()"
},
"expression": {
// If engineering, check second condition
"condition_expression": {
"clauses": [
{
"condition": {
// Second condition: Seniority is senior+
"rule_v2": "users_requested_for[0].custom_attributes.seniority_level IN [\"Senior\", \"Staff\", \"Principal\"]"
},
"expression": {
"auto_approve_expression": {}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}
}
],
"default_expression": {
"manager_expression": {}
}
}
}What this does:
- Senior+ Engineering: Auto-approve
- Junior Engineering: Manager approval
- All other departments: Manager approval
Common Patterns
Pattern 1: Tiered Access by Seniority
{
"rule_v2": "users_requested_for[0].custom_attributes.seniority_level IN [\"VP\", \"SVP\", \"C-Level\"]"
}
// Auto-approve for executives, else require approvalPattern 2: Contractor Restrictions
{
"rule_v2": "users_requested_for[0].is_full_time_employee == true"
}
// Auto-approve for FTE, require approval for contractorsPattern 3: Department-Specific Rules
{
"rule_v2": "users_requested_for[0].department.$LOWERCASE() == \"sales\".$LOWERCASE()"
}
// Sales gets different approval flowPattern 4: Self-Service by Manager
{
"rule_v2": "users_requested_for[0].manager_email == requestor.email_addr"
}
// Manager requesting for direct report auto-approvesPattern 5: Role-Specific Approval
{
"rule_v2": "approval_request.approvable_entity.app_entity.role_canonical_name_to_provision.$LOWERCASE() == \"basic\".$LOWERCASE()"
}
// Basic role gets manager approval, admin role gets dual approvalDebugging Conditions
If your condition isn't working:
-
Check attribute availability:
- Navigate to User Identity module
- Verify the attribute exists and has data
- Check exact spelling and casing
-
Test with simple conditions first:
- Start with:
users_requested_for[0].email_addr == "[email protected]" - Add complexity incrementally
- Start with:
-
Use $LOWERCASE() consistently:
- Always use for string comparisons
- Apply to both sides:
field.$LOWERCASE() == "value".$LOWERCASE()
-
Check array indexing:
users_requested_for[0]- First user (typical for individual requests)- If requesting for multiple people, may need different logic
-
Verify custom attributes:
- Custom attributes require
custom_attributes.prefix - Example:
users_requested_for[0].custom_attributes.seniority_level
- Custom attributes require
-
Contact Support:
- Provide the condition you're trying to write
- Share what behavior you expect vs what happens
- Include user examples that should/shouldn't match
Best Practices
1. Start with Built-In Workflows
Before creating custom workflows, check if a built-in workflow meets your needs. Built-in workflows are:
- Battle-tested and reliable
- Easier to understand for other admins
- Maintained by Moveworks
2. Keep It Simple
Complex approval workflows can:
- Slow down access provisioning
- Confuse users
- Be hard to troubleshoot
Ask yourself: "What's the minimum approval needed to keep us secure and compliant?"
3. Test Thoroughly
Before deploying to production:
- Create a test application
- Assign your custom workflow
- Test with different user types (employee, contractor, different departments)
- Verify notifications go to the right people
- Check that auto-approves work as expected
4. Document Your Workflows
In the workflow name or description, note:
- What this workflow does
- When to use it
- Who the approvers are
Example: Sales_Manager_Then_VP - "For expensive sales tools. Manager approves first, then Sales VP must also approve."
5. Use Descriptive Names
Your future self (and other admins) will thank you.
✅ Good:
Contractor_Manager_ApprovalEngineering_Tools_CTO_ApprovalSensitive_Data_Dual_Approval
❌ Bad:
Custom1New_Workflow_TestABC_Approval
6. Monitor Approval Response Times
If approvals are taking too long:
- Consider auto-approval for low-risk items
- Add parallel approval (1 of N) instead of sequential
- Check if approval groups are too large
7. Regular Review
Quarterly, review:
- Which workflows are being used
- Approval response times
- Workflows that auto-deny frequently (may need adjustment)
- Unused custom workflows (can be deleted)
Troubleshooting
Issue: Approvals Going to Wrong Person
Check:
- User's manager is correctly set in identity system
- App Admin email addresses are configured in software settings
- Custom workflow condition logic is correct
- Integration ID is correct for approval groups
Issue: Approvals Not Sending
Check:
- Workflow is assigned to the software/group
- Approver has access to the chat platform (Slack/Teams)
- Moveworks bot can message the approver
- No typos in email addresses
Issue: Auto-Approve Not Working
Check:
- Workflow is correctly configured as
auto_approve_expression - Conditions are evaluating to true (check user attributes)
- No conflicting approval requirements
- Workflow is saved and assigned
Issue: Sequential Approval Stuck
Check:
- First approver completed their approval
- Second approver is reachable
- Workflow JSON is correctly formatted
- No errors in workflow evaluation (check logs)
Getting Help
Need assistance with custom workflows?
Contact Moveworks Support with:
- Description of your desired approval flow
- User scenarios (who should approve in what situations)
- Current workflow JSON (if you have one)
- Specific error messages or unexpected behavior
Related Documentation
Updated about 2 months ago