Skip to main content

UpdateProcessDefinitionCommand

Overview

Updates an existing process definition.

Purpose

Modifies the BPMN XML, configuration, or metadata of an existing process definition. Creates a new version while preserving existing instances.

Command Type

CB.Administration.Api.Commands.BPM.Process.UpdateProcessDefinitiionCommand


Request

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Loan Approval Workflow v2",
"description": "Updated with automated checks",
"data": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bpmn:definitions>...</bpmn:definitions>",
"isEnabled": true,
"isEventCheck": false,
"conflictPolicy": 1,
"permission": "bnk_approve_loan",
"entityType": 1,
"processType": 0,
"triggerEvent": 0
}
}

Request Fields (data object)

FieldTypeRequiredDefaultDescription
idlongYesID of the process definition to update
namestringYesUpdated process name
datastringYesThe full BPMN XML content of the process
descriptionstringNo(unchanged)Human-readable description
categorystringNo(unchanged)Grouping category shown in the designer
permissionstringNo(unchanged)Permission code(s) required to interact with tasks. Comma-separated for multiple (e.g. "bnk_approve_loan,bnk_manage_loan"). Acts as process-level fallback when individual task permissions are not set.
entityTypeintNo(unchanged)Entity type this process applies to (ProcessEntityType enum, e.g. 1 = LoanAccount)
isEnabledboolNotrueWhether the process is enabled for new instances
isEventCheckboolNofalseWhen true, this process can only be started by system events — manual starts via the UI or API are blocked. See IsEventCheck below.
processTypeintNo0 (MANUAL)0 = Manual, 1 = Scheduled, 2 = EventDriven
triggerEventintNo0 (None)The ProcessDefinitionTriggerEventsEnum value that auto-starts this process (e.g. 2500 = OnMandateInitiationReceived). Only relevant when processType = EventDriven
conflictPolicyintNo(unchanged)What to do when an instance for the same entity already exists. See Conflict Policy below.
contextstringNo{}Default context JSON pre-loaded into every new process instance
contextLoaderstringNo""Context loader key that populates process variables at start time
scheduleobjectConditionalRequired when processType = 1 (Scheduled). Schedule settings object (frequency, time, timezone). See Scheduling below
enabledboolNotrueWhether the Hangfire recurring job is active. Only used when processType = Scheduled

IsEventCheck

When isEventCheck is set to true on a process definition, the process can only be started by an automatic system event (e.g. a loan state change, a webhook callback). Any attempt to start it manually through StartProcessInstanceCommand will be rejected with a 400 response:

{
"isSuccessful": false,
"statusCode": "Request_Is_Not_Valid",
"message": "Process 'Loan Auto-Review' can only be triggered by system events and cannot be started manually."
}

When to use: Set isEventCheck: true for processes that must always fire from a specific business event and should never be started ad-hoc (e.g. a compliance audit process that must only run when triggered by a specific transaction).


Conflict Policy

The conflictPolicy field controls what happens when StartProcessInstanceCommand is called for an entity that already has an active instance of this process definition (same entityType + entityId).

ValueIntNameBehaviour
AllowMultipleInstances0Allow Multiple(default) Start a new instance regardless of any existing ones
Reject1RejectReturn an error if an active instance already exists; the caller gets the existing instance ID
ReuseExisting2Reuse ExistingReturn the existing active instance without starting a new one
TerminateAndRestart3Terminate and RestartCancel the existing active instance and start a fresh one

Active instance means any instance with status NOT_STARTED, RUNNING, or WAITING.

Conflict Policy Decision Guide

Does this process need to run in parallel for the same entity?
├── Yes → AllowMultipleInstances (0) e.g. multiple independent document uploads
└── No
├── Should duplicate requests be silently ignored?
│ └── Yes → ReuseExisting (2) e.g. idempotent approval kick-off
├── Should duplicate requests be explicitly rejected?
│ └── Yes → Reject (1) e.g. strict single-instance compliance workflow
└── Should a new request restart from scratch?
└── Yes → TerminateAndRestart (3) e.g. re-triggerable review process

Request Example — Setting Conflict Policy

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Loan Approval Workflow",
"data": "<?xml version=\"1.0\"?>...",
"conflictPolicy": 1,
"isEventCheck": false,
"permission": "bnk_approve_loan,bnk_manage_loan",
"isEnabled": true
}
}

Permission Cascade

The permission field on a process definition acts as a fallback permission for task-level access control. The engine uses a 3-tier cascade when deciding if a user may interact with a waiting task:

  1. Task-level permission — permission code set directly on the BPMN userTask element (customProperty: permission)
  2. Process-level permissionpermission field on the ProcessDefinitiion record (this field) — used when the task has no explicit permission
  3. No permission check — if neither is set, any authenticated user may act on the task

Tip: Use the backPermissions array returned by GetProcessDefinitiionByIdQuery to see the resolved list of individual permission codes.


Versioning Behavior

When updating a process definition:

  • New Version Created: A new version number is assigned
  • Existing Instances Preserved: Running instances continue with old version
  • New Instances Use New Version: Future instances use updated definition

Version Strategy

Version 1 (Original)
├── Instance A (running) ─── continues with V1
├── Instance B (running) ─── continues with V1
└── Instance C (completed) ─ remains V1

Update Process Definition ➜ Version 2 Created

Version 2 (Updated)
├── Instance D (new) ─────── uses V2
└── Instance E (new) ─────── uses V2

Version 1
├── Instance A (still running V1)
└── Instance B (still running V1)

Response

{
"isSuccessful": true,
"message": "Process definition updated successfully",
"statusCode": "00",
"data": {
"id": 456,
"version": 2,
"previousVersion": 1,
"activeInstances": 5,
"warningMessage": "5 active instances still running version 1"
}
}

Response Fields

FieldTypeDescription
idlongProcess definition ID
versionintNew version number
previousVersionintPrevious version number
activeInstancesintNumber of instances still running old version
warningMessagestringWarning about active instances on old version

Error Responses

Process Definition Not Found

{
"isSuccessful": false,
"message": "Process definition with ID 456 not found",
"statusCode": "404"
}

Invalid Update (Breaking Change)

{
"isSuccessful": false,
"message": "Cannot update: Breaking changes detected",
"statusCode": "40",
"data": {
"breakingChanges": [
"Start event 'StartEvent_1' removed",
"User task 'Task_Approve' references removed"
]
}
}

Invalid BPMN XML

{
"isSuccessful": false,
"message": "Invalid BPMN XML: Missing end event",
"statusCode": "40",
"data": {
"validationErrors": [
"At least one end event required",
"Sequence flow 'Flow_5' has invalid target"
]
}
}

Update Scenarios

1. Update BPMN Logic Only

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Loan Approval Workflow",
"data": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bpmn:definitions>...</bpmn:definitions>"
}
}

2. Update Description Only

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Loan Approval Workflow",
"data": "<?xml version=\"1.0\"?>...",
"description": "Updated with additional compliance checks"
}
}

3. Make Event-Only (block manual starts)

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Mandate Cancellation Handler",
"data": "<?xml version=\"1.0\"?>...",
"isEventCheck": true,
"processType": 2,
"triggerEvent": 2505
}
}

4. Deactivate Process

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Loan Approval Workflow",
"data": "<?xml version=\"1.0\"?>...",
"isEnabled": false
}
}

5. Comprehensive Update

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Loan Approval Workflow v3",
"description": "Complete redesign with parallel approval",
"category": "Lending",
"data": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bpmn:definitions>...</bpmn:definitions>",
"isEnabled": true,
"isEventCheck": false,
"conflictPolicy": 2,
"permission": "bnk_approve_loan",
"entityType": 1,
"processType": 0,
"triggerEvent": 0
}
}

Scheduling

When processType is 1 (Scheduled), a schedule object is required. The schedule controls when Hangfire automatically starts new process instances.

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Daily Reconciliation",
"data": "<?xml version=\"1.0\"?>...",
"processType": 1,
"enabled": true,
"context": "{\"reportDate\": \"today\"}",
"schedule": {
"frequency": "daily",
"time": "00:00",
"timezone": "Africa/Lagos"
}
}
}
Schedule FieldDescription
frequency"daily", "weekly", "monthly", or a Quartz cron expression
timeTime of day in HH:mm format
timezoneIANA timezone name (e.g. "Africa/Lagos", "UTC")

For event-driven processes (processType = 2), set triggerEvent to the ProcessDefinitionTriggerEventsEnum value. For example, 2505 fires the process when an NPS mandate cancellation is received.


Best Practices

✅ Do's

  1. Always include name and data — both are mandatory fields.

  2. Test with isEnabled: false before activating a redesigned process:

    { "id": 456, "name": "...", "data": "...", "isEnabled": false }
  3. Use isEventCheck: true for processes that must only start from system events, never manually.

  4. Choose the right conflictPolicy — see the Conflict Policy section above.

  5. Incremental updates: Make small, testable changes rather than rewriting the entire process at once.

❌ Don'ts

  1. Don't update production without testing
  2. Don't ignore breaking change warnings
  3. Don't remove tasks referenced by active instances
  4. Don't change critical task IDs without migration plan
  5. Don't update during peak hours - Schedule maintenance windows

Version Migration Strategy

Handling Active Instances

When you update a process with active instances:

Option 1: Let Them Complete (Recommended)

1. Update to V2
2. Wait for V1 instances to complete naturally
3. Monitor completion in GetProcessInstanceListQuery

Option 2: Graceful Migration

1. Update to V2 with isActive=false
2. Signal all V1 instances to reach completion
3. Activate V2 after V1 instances complete

Option 3: Force Migration (Use with caution)

1. Cancel all V1 instances
2. Restart them with V2
3. Only for non-critical processes

Breaking Changes Detection

The system detects potentially breaking changes:

Structural Changes

  • ❌ Removing start/end events
  • ❌ Removing user tasks referenced in active instances
  • ❌ Changing task IDs that active instances depend on
  • ❌ Removing variables used by active instances

Safe Changes

  • ✅ Adding new tasks
  • ✅ Adding new variables
  • ✅ Updating task descriptions
  • ✅ Adding parallel paths
  • ✅ Modifying metadata

Example: Adding Parallel Approval

Version 1 (Sequential):

<process>
<startEvent id="start"/>
<userTask id="manager_approval" name="Manager Approval"/>
<userTask id="director_approval" name="Director Approval"/>
<endEvent id="end"/>

<sequenceFlow sourceRef="start" targetRef="manager_approval"/>
<sequenceFlow sourceRef="manager_approval" targetRef="director_approval"/>
<sequenceFlow sourceRef="director_approval" targetRef="end"/>
</process>

Version 2 (Parallel):

<process>
<startEvent id="start"/>
<parallelGateway id="fork"/>
<userTask id="manager_approval" name="Manager Approval"/>
<userTask id="director_approval" name="Director Approval"/>
<parallelGateway id="join"/>
<endEvent id="end"/>

<sequenceFlow sourceRef="start" targetRef="fork"/>
<sequenceFlow sourceRef="fork" targetRef="manager_approval"/>
<sequenceFlow sourceRef="fork" targetRef="director_approval"/>
<sequenceFlow sourceRef="manager_approval" targetRef="join"/>
<sequenceFlow sourceRef="director_approval" targetRef="join"/>
<sequenceFlow sourceRef="join" targetRef="end"/>
</process>

Update Command:

{
"cmd": "UpdateProcessDefinitiionCommand",
"data": {
"id": 456,
"name": "Loan Approval Workflow - Parallel",
"bpmnXml": "<?xml version=\"1.0\"...>",
"metadata": {
"version": "2.0.0",
"changelog": "Changed from sequential to parallel approval to reduce processing time"
}
}
}


Last Updated: January 6, 2026