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)
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | long | Yes | — | ID of the process definition to update |
name | string | Yes | — | Updated process name |
data | string | Yes | — | The full BPMN XML content of the process |
description | string | No | (unchanged) | Human-readable description |
category | string | No | (unchanged) | Grouping category shown in the designer |
permission | string | No | (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. |
entityType | int | No | (unchanged) | Entity type this process applies to (ProcessEntityType enum, e.g. 1 = LoanAccount) |
isEnabled | bool | No | true | Whether the process is enabled for new instances |
isEventCheck | bool | No | false | When true, this process can only be started by system events — manual starts via the UI or API are blocked. See IsEventCheck below. |
processType | int | No | 0 (MANUAL) | 0 = Manual, 1 = Scheduled, 2 = EventDriven |
triggerEvent | int | No | 0 (None) | The ProcessDefinitionTriggerEventsEnum value that auto-starts this process (e.g. 2500 = OnMandateInitiationReceived). Only relevant when processType = EventDriven |
conflictPolicy | int | No | (unchanged) | What to do when an instance for the same entity already exists. See Conflict Policy below. |
context | string | No | {} | Default context JSON pre-loaded into every new process instance |
contextLoader | string | No | "" | Context loader key that populates process variables at start time |
schedule | object | Conditional | — | Required when processType = 1 (Scheduled). Schedule settings object (frequency, time, timezone). See Scheduling below |
enabled | bool | No | true | Whether 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).
| Value | Int | Name | Behaviour |
|---|---|---|---|
AllowMultipleInstances | 0 | Allow Multiple | (default) Start a new instance regardless of any existing ones |
Reject | 1 | Reject | Return an error if an active instance already exists; the caller gets the existing instance ID |
ReuseExisting | 2 | Reuse Existing | Return the existing active instance without starting a new one |
TerminateAndRestart | 3 | Terminate and Restart | Cancel the existing active instance and start a fresh one |
Active instance means any instance with status
NOT_STARTED,RUNNING, orWAITING.
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:
- Task-level permission — permission code set directly on the BPMN
userTaskelement (customProperty: permission) - Process-level permission —
permissionfield on theProcessDefinitiionrecord (this field) — used when the task has no explicit permission - No permission check — if neither is set, any authenticated user may act on the task
Tip: Use the
backPermissionsarray returned byGetProcessDefinitiionByIdQueryto 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
| Field | Type | Description |
|---|---|---|
id | long | Process definition ID |
version | int | New version number |
previousVersion | int | Previous version number |
activeInstances | int | Number of instances still running old version |
warningMessage | string | Warning 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 Field | Description |
|---|---|
frequency | "daily", "weekly", "monthly", or a Quartz cron expression |
time | Time of day in HH:mm format |
timezone | IANA 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
-
Always include
nameanddata— both are mandatory fields. -
Test with
isEnabled: falsebefore activating a redesigned process:{ "id": 456, "name": "...", "data": "...", "isEnabled": false } -
Use
isEventCheck: truefor processes that must only start from system events, never manually. -
Choose the right
conflictPolicy— see the Conflict Policy section above. -
Incremental updates: Make small, testable changes rather than rewriting the entire process at once.
❌ Don'ts
- Don't update production without testing
- Don't ignore breaking change warnings
- Don't remove tasks referenced by active instances
- Don't change critical task IDs without migration plan
- 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"
}
}
}
Related Commands
- CreateProcessDefinitionCommand - Create new process
- GetProcessDefinitionByIdQuery - View current version
- RenameProcessDefinitionCommand - Rename without versioning
GetProcessInstanceListQuery- Check active instances
Last Updated: January 6, 2026