TL;DR
A workflow definition is a blueprint: trigger event, optional conditions, and a sequence of steps. Each step has a type (approval, notification, Groovy, REST), an assignee rule, and transition conditions.
Trigger events come from IM (plan.submitted, statement.published, quota.updated, etc.). Conditions filter which records trigger the workflow using Groovy logic.
Assignee rules determine who receives approval tasks: specific user, role-based lookup, or hierarchy-based lookup (most common in IM).
Workflow versioning is critical: active workflows run on the deployed version. Updating a definition applies to new instances only — in-flight instances continue on the old version.

The Structure of a Workflow Definition

A workflow definition is a declarative blueprint that describes how IM events should be processed. The definition consists of four parts:

  1. Metadata: Name, description, version, status (active/inactive).
  2. Trigger: The IM event that initiates the workflow.
  3. Conditions: Optional Groovy logic that filters which triggered records actually start a workflow instance.
  4. Steps: The sequence of actions the workflow takes (approval, notification, Groovy script, REST call, etc.).

Here's a simplified JSON-style representation of a workflow definition structure:

{
  "name": "Plan Approval Workflow",
  "description": "Route compensation plans through manager and director approval",
  "version": "1.2",
  "status": "ACTIVE",
  "triggerEvent": "plan.submitted_for_approval",
  "conditions": {
    "filterLogic": "AND",
    "rules": [
      { "field": "plan.type", "operator": "=", "value": "INCENTIVE" },
      { "field": "plan.status", "operator": "=", "value": "SUBMITTED" }
    ]
  },
  "steps": [
    { ... step 1 definition ... },
    { ... step 2 definition ... }
  ]
}

Trigger Events: What IM Events Can Fire Workflows

A workflow definition must specify which IM event triggers it. Advanced Workflow listens for these events published by IM. When an event occurs that matches the trigger event, a new workflow instance is created.

Common IM trigger events (not exhaustive):

Plan Events:

  • plan.created — A new plan is created in IM.
  • plan.submitted_for_approval — A plan is submitted to the approval chain.
  • plan.approved — A plan completes approval and becomes active.
  • plan.rejected — A plan approval is rejected.
  • plan.activated — A plan is activated (becomes effective for participants).
  • plan.deactivated — A plan is deactivated (end of period).

Calculation Events:

  • calculation.started — A calculation run begins.
  • calculation.completed — A calculation run finishes (all periods/participants processed).
  • calculation.failed — A calculation run terminates with errors.

Statement Events:

  • statement.generated — A statement is created for a participant in a period.
  • statement.published — A statement is published and visible to the participant.
  • statement.updated — A statement is revised (correction after initial publication).

Quota/Participant Events:

  • quota.updated — A participant's quota is changed.
  • participant.updated — Participant master data is changed (manager, territory, etc.).
  • participant.hired — A new participant is added to the system.
  • participant.terminated — A participant is terminated.

Dispute Events:

  • dispute.submitted — A participant files a dispute.
  • dispute.resolved — A dispute is approved or rejected.

Period Events:

  • period.opened — A new compensation period is opened.
  • period.closed — A period is closed (no more changes).
  • period.finalized — A period is finalized and archived.

Conditions: Filtering Which Events Trigger Workflows

A trigger event fires frequently. For example, plan.submitted_for_approval fires every time any plan is submitted — potentially dozens of times a day. Without conditions, every plan submission would trigger the workflow, even if you only want to trigger for certain plan types or regions.

Conditions allow you to filter which triggered events actually create a workflow instance. Conditions are Groovy logic that evaluates the triggered record's data and returns true (start workflow) or false (skip workflow).

Simple Condition Example

Trigger: plan.submitted_for_approval

Condition: Only trigger if plan.type = "INCENTIVE" (ignore administrative plans).

// Condition logic (Groovy)
plan.type == "INCENTIVE"

Complex Condition Example

Trigger: statement.published

Condition: Only trigger if the statement commission > $1000 AND the participant is in the US region.

// Condition logic (Groovy)
statement?.commissionAmount != null &&
statement.commissionAmount > 1000 &&
participant?.region == "US"

Notice the null-safe navigation (?.) to prevent NullPointerException if statement or participant is missing.

Conditions with Negation

Trigger: participant.updated

Condition: Trigger only if the participant is NOT being terminated (don't process workflows for terminated participants).

// Condition logic (Groovy)
participant?.status != "TERMINATED" &&
participant?.status != "INACTIVE"

Steps: The Building Blocks of Workflow Logic

A workflow definition is a sequence of steps. Each step is an action: approval, notification, Groovy script, REST API call, or a decision point. The workflow executes steps in order unless a condition causes a branch or return.

Step anatomy:

  • Name: Human-readable label for the step ("Manager Approval", "Send Confirmation Email", "Validate Quota").
  • Type: What the step does (APPROVAL, NOTIFICATION, GROOVY_SCRIPT, REST_CALL, CONDITION, etc.).
  • Configuration: Type-specific settings (for approval: assignee rule, SLA, escalation; for notification: recipients, subject, body; for Groovy: script code).
  • Transition Rules: What happens when the step completes (go to next step, return to previous, end workflow, branch based on condition).

Approval Steps: Assignee Rules

An approval step requires you to specify who the approver is. Advanced Workflow supports three assignee rule types:

Assignee Rule Type 1: Specific User

Hard-code a user ID or email.

Configuration:

assigneeRule: {
  type: "SPECIFIC_USER",
  userId: "compensation-director@company.com"
}

Use case: Static approval paths. Example: All high-value exceptions always escalate to the compensation director, not to the participant's manager.

Risk: If the user leaves, you must manually update the workflow definition.

Assignee Rule Type 2: Role-Based Lookup

Find users by role. The workflow looks up all users with a specific role and assigns the approval to them (or to any one of them).

Configuration:

assigneeRule: {
  type: "ROLE_BASED",
  roleName: "Compensation_Analyst",
  region: "EMEA"  // optional: filter to a specific region
}

Use case: When multiple people can approve and any one is acceptable. Example: Assign dispute approvals to anyone with the "Compensation_Analyst" role in the participant's region.

Risk: If no user has the role, assignment fails.

Assignee Rule Type 3: Hierarchy-Based Lookup (Most Common in IM)

Navigate the participant's org hierarchy to find the approver. This is the most common pattern in IM because approval chains almost always follow reporting lines.

Configuration:

assigneeRule: {
  type: "HIERARCHY_BASED",
  path: "participant.manager.id"  // Direct manager
}

// Variations:
path: "participant.manager.manager.id"  // Skip-level (director)
path: "participant.manager.manager.manager.id"  // Two levels up

Use case: Standard approval chains. Manager approves first, then director for high-value items.

Risk: If the manager ID is null, the assignment fails and the workflow hangs. Robust workflows include null checks and fallback rules.

Hierarchy Assignment with Fallback Logic

Robust approval workflows use Groovy to implement fallback logic: if the direct manager is missing, escalate to the director. If the director is missing, escalate to the VP. If no one is found, escalate to the compensation team.

// Groovy assignee rule with fallback
def approver = null

if (participant?.manager?.id) {
  approver = participant.manager.id
} else if (participant?.manager?.manager?.id) {
  approver = participant.manager.manager.id
} else if (participant?.businessUnit?.head?.id) {
  approver = participant.businessUnit.head.id
} else {
  approver = "compensation-team@company.com"
}

return approver

This script tries to find an approver in order of preference. If all fail, it defaults to the compensation team email. This prevents the workflow from hanging due to missing hierarchy data.

Notification Steps: Recipients and Templates

A notification step sends a message to one or more recipients. Configuration includes:

Recipient Definition (Groovy):

// Always send to participant
recipients = [participant.email]

// Conditionally add manager if commission is high
if (statement?.commissionAmount > 10000) {
  recipients.add(participant.manager.email)
}

// Conditionally add compensation team if outlier detected
if (isOutlier(statement.commissionAmount)) {
  recipients.add("compensation-team@company.com")
}

return recipients

Message Template:

subject: "Your ${plan.period} Statement is Ready"

body:
Hi ${participant.name},

Your compensation statement for ${plan.period} is now available.

Commission Amount: $${formatCurrency(statement.commissionAmount)}
Quota Achievement: ${statement.quotaAchievement}%
Territory: ${quota.territory}

Log in to SuccessFactors to view your detailed statement breakdown.

Questions? Contact: ${participant.manager.email} or compensation-team@company.com

Best regards,
Compensation Team

Context variables (${...}) are replaced at runtime with actual participant and plan data. Common variables:

  • ${participant.name}, ${participant.email}, ${participant.id}, ${participant.manager.name}
  • ${plan.name}, ${plan.period}, ${plan.type}, ${plan.startDate}, ${plan.endDate}
  • ${statement.commissionAmount}, ${statement.quotaAchievement}, ${statement.bonus}
  • ${workflow.createdAt}, ${workflow.completedAt}, ${workflow.submittedBy}

Groovy Script Steps: Custom Logic

A Groovy script step executes custom code. Groovy steps are used for:

  • Data transformations (convert commission to currency format, calculate percentage change).
  • Validations (check if participant is eligible, check if quota is valid).
  • Complex routing logic (determine approver based on multiple conditions).
  • External API calls (call payroll system, CRM, data warehouse).

Example Groovy Step: Validate and Route to Correct Approver

// Groovy script step in an approval workflow
// Determines if we should send to manager or director based on plan value

import groovy.json.JsonSlurper

def approvingRole = null

if (plan?.annualValue == null) {
  log.error("Plan has no annual value: " + plan.id)
  approvingRole = "ESCALATE_TO_DIRECTOR"
} else if (plan.annualValue < 100000) {
  approvingRole = "MANAGER"
} else if (plan.annualValue < 500000) {
  approvingRole = "DIRECTOR"
} else {
  approvingRole = "VP"
}

// Store for use in next step
workflow.approvalLevel = approvingRole

return approvingRole

Context Variables Reference Table

Category Variable Type Example Value
Participant ${participant.id} String P12345
Participant ${participant.name} String John Smith
Participant ${participant.email} String john.smith@company.com
Participant ${participant.manager.id} String M98765
Participant ${participant.region} String EMEA, APAC, AMER
Plan ${plan.id} String PLAN_Q2_2026
Plan ${plan.name} String Q2 2026 Sales Incentive
Plan ${plan.period} String Q2 2026
Plan ${plan.annualValue} Decimal 250000.00
Statement ${statement.commissionAmount} Decimal 5240.50
Statement ${statement.quotaAchievement} Decimal 115.5
Workflow ${workflow.id} String WF_UUID_123456
Workflow ${workflow.createdAt} ISO8601 DateTime 2026-04-12T09:15:00Z
Workflow ${workflow.submittedBy} String (User ID) admin@company.com

Complete Worked Example: Two-Step Plan Approval Workflow

Here's a complete workflow definition for a realistic scenario: a compensation plan must be approved by the manager, then the director (if plan value > $500K).

Workflow Definition

name: "Plan Approval Workflow"
description: "Route compensation plans through manager and director approval"
version: "1.0"
status: "ACTIVE"

triggerEvent: "plan.submitted_for_approval"

conditions:
  # Only trigger for incentive plans, not admin plans
  filterLogic: "AND"
  rules:
    - field: "plan.type"
      operator: "="
      value: "INCENTIVE"
    - field: "plan.status"
      operator: "="
      value: "SUBMITTED"

steps:
  - stepNumber: 1
    name: "Manager Approval"
    type: "APPROVAL"
    description: "Route to the participant's direct manager for initial review"
    assigneeRule:
      type: "HIERARCHY_BASED"
      path: "participant.manager.id"
    sla:
      duration: 3
      unit: "BUSINESS_DAYS"
      timeZone: "participant.timeZone"
    escalation:
      afterDays: 3
      action: "ESCALATE_TO_MANAGER_MANAGER"
      escalateToPath: "participant.manager.manager.id"
    taskSubject: "Plan Approval Needed: ${plan.name}"
    taskBody: |
      Hi ${participant.manager.name},

      ${participant.name} has submitted their compensation plan for Q2 2026 approval.
      Plan Value: $${formatCurrency(plan.annualValue)}

      Please review and approve or reject.
    onApprove:
      nextStep: 2
    onReject:
      action: "END_WORKFLOW"
      notifyInitiator: true
      message: "Manager has rejected the plan submission."

  - stepNumber: 2
    name: "Conditional Director Review"
    type: "GROOVY_SCRIPT"
    description: "Check plan value. If >= $500K, route to director. Otherwise skip to final notification."
    script: |
      if (plan?.annualValue >= 500000) {
        workflow.requiresDirectorApproval = true
        return "DIRECTOR_REVIEW"
      } else {
        workflow.requiresDirectorApproval = false
        return "SKIP_TO_NOTIFICATION"
      }
    transitions:
      DIRECTOR_REVIEW: 3
      SKIP_TO_NOTIFICATION: 4

  - stepNumber: 3
    name: "Director Approval"
    type: "APPROVAL"
    description: "High-value plans require director sign-off"
    condition: "workflow.requiresDirectorApproval == true"
    assigneeRule:
      type: "HIERARCHY_BASED"
      path: "participant.manager.manager.id"
    sla:
      duration: 5
      unit: "BUSINESS_DAYS"
    escalation:
      afterDays: 5
      action: "AUTO_APPROVE"
    taskSubject: "High-Value Plan Approval: ${plan.name} ($${formatCurrency(plan.annualValue)})"
    taskBody: |
      Hi ${participant.manager.manager.name},

      A high-value plan requires your approval.
      Participant: ${participant.name}
      Plan: ${plan.name}
      Value: $${formatCurrency(plan.annualValue)}

      Manager approved on ${workflow.step1CompletedAt}.
      Please approve or return for revision.
    onApprove:
      nextStep: 4
    onReject:
      action: "RETURN_TO_PREVIOUS_STEP"
      previousStep: 1
      message: "Director requests changes. Manager please revise and resubmit."

  - stepNumber: 4
    name: "Send Approval Notification"
    type: "NOTIFICATION"
    description: "Notify participant that plan has been approved"
    recipientScript: |
      recipients = [participant.email]
      if (participant.manager?.email) {
        recipients.add(participant.manager.email)
      }
      return recipients
    channel: "EMAIL"
    subject: "Plan Approved: ${plan.name}"
    body: |
      Hi ${participant.name},

      Your compensation plan for ${plan.period} has been approved and is now active.

      Plan Name: ${plan.name}
      Period: ${plan.period}
      Start Date: ${plan.startDate}

      Log in to SuccessFactors to view plan details and target commission structure.

      Questions? Contact your manager or the compensation team.
    onComplete:
      action: "END_WORKFLOW"
      workflowOutcome: "APPROVED"
      returnToIM: true

Testing Workflow Definitions Before Activation

Before you activate a workflow definition in production, you must test it in a sandbox environment. Testing includes:

Sandbox Run with Test Participant: Create a test participant in the sandbox who has a complete hierarchy (manager, director, VP). Submit a test plan that triggers the workflow. Walk through each approval step. Verify:

  • Workflow fires on the correct trigger event.
  • Conditions work as expected (workflow fires for INCENTIVE plans, doesn't fire for ADMIN plans).
  • Approvers are correctly identified (first approver is the manager, second is the director for high-value plans).
  • Approval tasks appear in the correct approver's inbox.
  • Task subject and body contain correct context variables (participant name, plan name, etc.).
  • Approval actions work (Approve moves to next step, Reject ends workflow).
  • SLA timers are set correctly.
  • Escalation logic works (after X days, escalate or auto-approve).

Edge Case Testing: Test scenarios where hierarchy data is missing or unexpected:

  • Test participant with no manager. Verify fallback logic routes to director or compensation team.
  • Test participant whose manager is also a participant. Verify no circular routing.
  • Test participant with terminated manager. Verify escalation skips terminated user.
  • Test boundary conditions (plan.annualValue = exactly 500000, achievement = exactly 100%, etc.).
ℹ️Sandbox testing is critical: Never activate a workflow in production without full sandbox validation. Workflows run at scale — a bug affects all participants simultaneously. Allocate 2–3 weeks of testing time for a complex workflow.

Workflow Versioning: A Critical Operational Detail

Workflow versioning is one of the most important concepts in Advanced Workflow operations, and it's often misunderstood.

Key rule: In-flight workflow instances run on the version of the definition that was active when the instance started. Updating the definition does not affect running instances.

Example scenario:

  • Monday 9am: Workflow "Plan Approval" v1.0 is active. Participant A submits a plan. A workflow instance (Instance #1) is created running on v1.0.
  • Monday 5pm: You discover a bug in v1.0 (approver name is wrong in the task subject). You create v1.1 with the bug fix and activate it.
  • Tuesday 9am: Participant B submits a plan. A workflow instance (Instance #2) is created running on v1.1 (the new version).
  • Tuesday 2pm: Instance #1 (Participant A's workflow) still runs on v1.0 with the bug. The manager sees the incorrect approver name in the task. Instance #2 (Participant B's workflow) runs on v1.1 and the manager sees the correct name.

This creates inconsistency. Participants submitted on different days see different task wording, different business logic, different approval requirements.

Strategies to minimize versioning pain:

Strategy 1: Get it right before activation. Spend enough time in sandbox testing that v1.0 is correct. Minimize the need to release v1.1, v1.2, etc. This is the ideal approach.

Strategy 2: Minor fixes only in new versions. Reserve new versions for bug fixes and wording changes. Don't change business logic (e.g., approval chain, routing) in new versions — this creates inconsistency between instances.

Strategy 3: Drain in-flight instances before major changes. If you must change business logic, wait until all in-flight instances complete. Then activate the new version. This is slow but ensures consistency.

Strategy 4: Plan versioning in advance. Design the workflow to be extensible. Use Groovy to encapsulate business logic so you can change behavior without changing the workflow structure. This allows you to update logic in v1.1 without affecting the approval chain structure.

⚠️Versioning risk: If you deploy a workflow with a critical bug and discover it after 100 instances are in-flight, you have two bad options: (1) leave the 100 instances running on the broken version and fix future instances on v1.1 (inconsistency), or (2) manually complete the 100 instances and restart them on v1.1 (operational overhead). Allocate extra time for sandbox testing to avoid this.

Activation and Deployment

Once a workflow definition is tested and ready, you activate it. Activation makes the workflow live — it will trigger on the specified event and process real participants and plans.

Deployment checklist before activation:

  • All sandbox test cases passed.
  • All approver hierarchies are correct in production.
  • All email addresses and role configurations are correct.
  • Notification templates reviewed and approved.
  • SLA timers and escalation rules validated.
  • Groovy scripts error-handled (no unguarded null accesses).
  • Documentation created (what the workflow does, how to troubleshoot, who to contact if stuck).
  • Support team trained on handling stuck approvals.

Key Takeaways

  • A workflow definition is a blueprint: trigger event → conditions → steps. Each step is an action with assignees, transitions, and error handling.
  • Trigger events come from IM. Conditions filter which triggered records create workflow instances using Groovy logic.
  • Assignee rules determine who receives approval tasks: specific user, role-based lookup, or hierarchy-based lookup (most common in IM).
  • Context variables (${participant.name}, ${plan.period}, ${statement.commissionAmount}, etc.) personalize approval tasks and notification content.
  • Workflow versioning is critical: in-flight instances run on the version active when they started. Updating the definition applies to new instances only.
  • Spend 2–3 weeks testing workflows in sandbox before production activation. Test normal cases and edge cases (missing hierarchy, circular reporting, etc.).