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

The Approval Flow

  1. User requests access (e.g., "I need Salesforce access")
  2. Moveworks evaluates the approval workflow configured for that resource
  3. Approval requests sent to the appropriate people based on the workflow
  4. Approvers receive notification in their chat platform (Slack, Teams, etc.)
  5. Approvers approve or deny with one click
  6. 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

WorkflowWho ApprovesWhen to UseExample Use Case
AUTO_APPROVENo one (automatic)Low-risk software everyone should have access toSlack, Zoom Basic, company wiki
AUTO_APPROVE_FULL_TIME_ELSE_MANAGERAuto for employees, Manager for contractorsStandard tools but contractors need reviewMicrosoft Office, standard SaaS tools
AUTO_APPROVE_FULL_TIME_ELSE_APP_ADMINAuto for employees, App Admin for contractorsIT-managed tools, contractors need special setupVPN 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

WorkflowWho ApprovesWhen to UseExample Use Case
MANAGERUser's direct managerManager knows if user needs this for their jobSalesforce, Jira, specialized tools
APP_ADMINApplication administratorsIT/app owner needs to provision or has technical knowledgeAdmin 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

WorkflowWho ApprovesWhen to UseExample Use Case
APP_ADMIN_THEN_MANAGERApp Admin first, then ManagerBoth IT and manager need to agree, IT checks firstProduction access, elevated permissions
MANAGER_THEN_DL_OWNERManager first, then Group OwnerAdding to sensitive groupsExecutive 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):

  1. Requester is already a member of a parent group OR
  2. Group explicitly allows self-service membership AND
  3. Group is public/visible AND
  4. 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:

WorkflowApproval LogicUse Case
STANDARD_WITH_FALLBACK_TO_MANAGERStandard trust check, but if Group Owner approval needed and owner is unavailable → Manager approvesGroups where manager can substitute for owner
MOST_RESTRICTIVE_WITH_FALLBACK_TO_MANAGERMost restrictive check, but Manager can approve if Group Owner unavailableSensitive groups with manager backup
MANAGER_THEN_DL_OWNERManager approves first, then Group Owner (sequential)Dual approval for sensitive groups
MANAGER_THEN_DL_OWNER_WITH_FALLBACK_TO_AUTO_APPROVEManager then Group Owner, but auto-approve if both unavailableFlexible group access with backup

Google Workspace Specific

WorkflowWho ApprovesWhen to Use
GSUITE_OPEN_OR_OWNERAuto if Google group is "Open", else Group OwnerGoogle 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:

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 NameApproval FlowBest For
AUTO_APPROVEAutomatic approvalLow-risk, widely available software
MANAGERDirect manager approvesStandard business applications
APP_ADMINApp administrators approveIT-managed or specialized tools
APP_ADMIN_THEN_MANAGERApp admin → Manager (sequential)High-risk software, dual approval needed
AUTO_APPROVE_FULL_TIME_ELSE_MANAGERAuto for FTE, Manager for contractorsStandard tools with contractor restrictions
AUTO_APPROVE_FULL_TIME_ELSE_APP_ADMINAuto for FTE, App Admin for contractorsIT tools with contractor restrictions
STANDARD_TRUST_MODELConditional auto-approve or Group OwnerStandard distribution lists
STANDARD_WITH_FALLBACK_TO_MANAGERConditional auto-approve or ManagerDistribution lists, manager fallback
MOST_RESTRICTIVE_TRUST_MODELStrict conditions or Group OwnerSensitive distribution lists
MOST_RESTRICTIVE_WITH_FALLBACK_TO_MANAGERStrict conditions or ManagerSensitive groups, manager fallback
MOST_RESTRICTIVE_WITH_FALLBACK_TO_DL_MANAGERStrict conditions → DL ManagerSensitive groups, DL manager fallback
LEAST_RESTRICTIVE_TRUST_MODELFlexible auto-approve or Group OwnerOpen/public distribution lists
MANAGER_THEN_DL_OWNERManager → Group Owner (sequential)Sensitive groups, dual approval
MANAGER_THEN_DL_OWNER_WITH_FALLBACK_TO_AUTO_APPROVEManager → Group Owner, or autoFlexible group access
GSUITE_OPEN_OR_OWNERAuto if open, else Group OwnerGoogle Workspace groups
ADD_TO_DL_APPROVALMost restrictive → Manager fallbackAdding users to distribution lists
REMOVE_FROM_DL_APPROVALMost restrictive → Manager fallbackRemoving users from distribution lists
CREATE_DL_APPROVALAutomatic approvalCreating new distribution lists
GET_DL_MANAGER_APPROVALDistribution List ManagerDL 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:

  1. Manager gets approval request
  2. Manager approves
  3. Then App Admin gets approval request
  4. App Admin approves
  5. 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:

  1. All 3 VPs get approval request simultaneously
  2. First VP to approve completes the approval
  3. Other VPs' requests are auto-dismissed
  4. 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:

  1. Define a group in your identity system (Okta, Azure AD, etc.) containing all potential approvers
  2. Configure how many group members must approve (number_required)
  3. All group members receive the approval request simultaneously
  4. Once the required number approve, access is granted
  5. Remaining approval requests are auto-dismissed

Key Parameters:

ParameterDescriptionExample Values
external_idThe group ID from your identity system00gq0p1j6jGsb0ZCO2p8 (Okta), sg-12345678 (AWS), [email protected] (Google)
integration_idYour identity system integration IDokta, azure_ad, google_workspace
number_requiredHow many members must approve1 (any one), 2 (any two), 3 (any three)
roleWhich group role can approveMEMBER (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:

  1. User requests production database access
  2. All 8 IT Security team members get approval request in Slack/Teams
  3. First 2 team members to approve complete the requirement
  4. Other 6 team members' requests are auto-dismissed
  5. 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_id for 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_Team
  • Sales_VP_Approval_For_CRM_Tools
  • Director_Plus_Auto_Approve

❌ Bad names:

  • Custom_Approval_1
  • New_Flow
  • Test

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

AttributeExample ValueUse 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].departmentEngineeringDepartment-based rules
users_requested_for[0].roleSoftware EngineerRole-based rules
users_requested_for[0].manager_email[email protected]Manager relationship checks
users_requested_for[0].is_full_time_employeetrueEmployee type checks
users_requested_for[0].work_statusFULL_TIMEWork status checks
users_requested_for[0].locationSan FranciscoLocation-based rules

Custom Attributes

AttributeExampleUse Case
users_requested_for[0].custom_attributes.seniority_levelDirectorSeniority-based approval
users_requested_for[0].custom_attributes.cost_center8000Budget approval routing
users_requested_for[0].custom_attributes.clearance_levelSecretSecurity clearance checks

See available attributes: User Identity Module

Request Attributes

AttributeExampleUse Case
approval_request.approvable_entity.app_entity.role_canonical_name_to_provisionadmin_roleRole-based approval
approval_request.approvable_entity.app_entity.nameSalesforceApp-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 == true

Email 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_addr

Relationship 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_chain

Role-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 approval

Pattern 2: Contractor Restrictions

{
  "rule_v2": "users_requested_for[0].is_full_time_employee == true"
}
// Auto-approve for FTE, require approval for contractors

Pattern 3: Department-Specific Rules

{
  "rule_v2": "users_requested_for[0].department.$LOWERCASE() == \"sales\".$LOWERCASE()"
}
// Sales gets different approval flow

Pattern 4: Self-Service by Manager

{
  "rule_v2": "users_requested_for[0].manager_email == requestor.email_addr"
}
// Manager requesting for direct report auto-approves

Pattern 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 approval

Debugging Conditions

If your condition isn't working:

  1. Check attribute availability:

    • Navigate to User Identity module
    • Verify the attribute exists and has data
    • Check exact spelling and casing
  2. Test with simple conditions first:

    • Start with: users_requested_for[0].email_addr == "[email protected]"
    • Add complexity incrementally
  3. Use $LOWERCASE() consistently:

    • Always use for string comparisons
    • Apply to both sides: field.$LOWERCASE() == "value".$LOWERCASE()
  4. Check array indexing:

    • users_requested_for[0] - First user (typical for individual requests)
    • If requesting for multiple people, may need different logic
  5. Verify custom attributes:

    • Custom attributes require custom_attributes. prefix
    • Example: users_requested_for[0].custom_attributes.seniority_level
  6. 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:

  1. Create a test application
  2. Assign your custom workflow
  3. Test with different user types (employee, contractor, different departments)
  4. Verify notifications go to the right people
  5. 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_Approval
  • Engineering_Tools_CTO_Approval
  • Sensitive_Data_Dual_Approval

Bad:

  • Custom1
  • New_Workflow_Test
  • ABC_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:

  1. User's manager is correctly set in identity system
  2. App Admin email addresses are configured in software settings
  3. Custom workflow condition logic is correct
  4. Integration ID is correct for approval groups

Issue: Approvals Not Sending

Check:

  1. Workflow is assigned to the software/group
  2. Approver has access to the chat platform (Slack/Teams)
  3. Moveworks bot can message the approver
  4. No typos in email addresses

Issue: Auto-Approve Not Working

Check:

  1. Workflow is correctly configured as auto_approve_expression
  2. Conditions are evaluating to true (check user attributes)
  3. No conflicting approval requirements
  4. Workflow is saved and assigned

Issue: Sequential Approval Stuck

Check:

  1. First approver completed their approval
  2. Second approver is reachable
  3. Workflow JSON is correctly formatted
  4. 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