Gateway - Flow Control and Routing
Gateways control the flow of process execution by enabling conditional routing, parallel execution, and flow merging. They act as decision points in your process.
Gateway Types
1. Exclusive Gateway (XOR)
Behavior: Selects exactly ONE outgoing path based on conditions
Use When: You need to choose one path from multiple options
2. Parallel Gateway (AND)
Behavior: Activates ALL outgoing paths simultaneously, waits for all incoming paths to complete
Use When: You need to execute multiple tasks in parallel
3. Inclusive Gateway (OR)
Behavior: Activates one or MORE outgoing paths based on conditions
Use When: Multiple paths may be valid simultaneously
Exclusive Gateway
The most commonly used gateway for decision-making.
Properties
Condition: Script that returns the flow name/ID to takeFormKey: Optional form for gateway configurationUserActions: Optional user actions at gatewayEntityState: State during gateway evaluationClientScript: Client-side script for UIResponsibleTeam/ResponsibleUser: Assignment for manual gateways
Basic Exclusive Gateway
<bpmn:exclusiveGateway id="Gateway_CheckAmount" name="High Value?" default="Flow_Standard">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
return loanAmount > 50000 ? 'Flow_HighValue' : 'Flow_Standard';
" />
</custom:properties>
</bpmn:extensionElements>
<bpmn:incoming>Flow_In</bpmn:incoming>
<bpmn:outgoing>Flow_HighValue</bpmn:outgoing>
<bpmn:outgoing>Flow_Standard</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_HighValue" name="High Value"
sourceRef="Gateway_CheckAmount" targetRef="Task_SeniorReview" />
<bpmn:sequenceFlow id="Flow_Standard" name="Standard"
sourceRef="Gateway_CheckAmount" targetRef="Task_StandardReview" />
Multi-Way Decision Gateway
<bpmn:exclusiveGateway id="Gateway_RiskLevel" name="Assess Risk" default="Flow_Rejected">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
if (creditScore >= 720 && debtToIncomeRatio < 36) {
return 'Flow_LowRisk';
} else if (creditScore >= 650 && debtToIncomeRatio < 43) {
return 'Flow_MediumRisk';
} else if (creditScore >= 580) {
return 'Flow_HighRisk';
}
return 'Flow_Rejected'; // Default to rejection
" />
</custom:properties>
</bpmn:extensionElements>
<bpmn:outgoing>Flow_LowRisk</bpmn:outgoing>
<bpmn:outgoing>Flow_MediumRisk</bpmn:outgoing>
<bpmn:outgoing>Flow_HighRisk</bpmn:outgoing>
<bpmn:outgoing>Flow_Rejected</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_LowRisk" name="Low Risk (Auto-Approve)"
sourceRef="Gateway_RiskLevel" targetRef="Task_AutoApprove" />
<bpmn:sequenceFlow id="Flow_MediumRisk" name="Medium Risk (Officer Review)"
sourceRef="Gateway_RiskLevel" targetRef="Task_OfficerReview" />
<bpmn:sequenceFlow id="Flow_HighRisk" name="High Risk (Manager Review)"
sourceRef="Gateway_RiskLevel" targetRef="Task_ManagerReview" />
<bpmn:sequenceFlow id="Flow_Rejected" name="Rejected"
sourceRef="Gateway_RiskLevel" targetRef="Task_SendRejection" />
Gateway with BankLingo Commands
<bpmn:exclusiveGateway id="Gateway_DynamicRouting" name="Dynamic Approval Path">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
// Call BankLingo command to determine routing
const routingDecision = doCmd('DetermineApprovalPath', {
loanAmount: loanAmount,
creditScore: creditScore,
customerSegment: customerSegment,
riskFactors: riskFactors
});
// Return the flow name from command result
return routingDecision.flowName;
" />
</custom:properties>
</bpmn:extensionElements>
<bpmn:outgoing>Flow_AutoApprove</bpmn:outgoing>
<bpmn:outgoing>Flow_StandardReview</bpmn:outgoing>
<bpmn:outgoing>Flow_EnhancedReview</bpmn:outgoing>
<bpmn:outgoing>Flow_Escalate</bpmn:outgoing>
</bpmn:exclusiveGateway>
Gateway Based on User Action
<!-- User Task -->
<bpmn:userTask id="Task_Review" name="Review Application">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="FormKey" value="review-form" />
<custom:property name="UserActions" value="Approve,Reject,RequestMoreInfo" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:userTask>
<bpmn:sequenceFlow sourceRef="Task_Review" targetRef="Gateway_Decision" />
<!-- Gateway checks user action -->
<bpmn:exclusiveGateway id="Gateway_Decision" name="Check Decision" default="Flow_MoreInfo">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
if (userAction === 'Approve') return 'Flow_Approved';
if (userAction === 'Reject') return 'Flow_Rejected';
return 'Flow_MoreInfo';
" />
</custom:properties>
</bpmn:extensionElements>
<bpmn:outgoing>Flow_Approved</bpmn:outgoing>
<bpmn:outgoing>Flow_Rejected</bpmn:outgoing>
<bpmn:outgoing>Flow_MoreInfo</bpmn:outgoing>
</bpmn:exclusiveGateway>
Parallel Gateway
Execute multiple tasks simultaneously.
Split - Start Parallel Execution
<bpmn:parallelGateway id="Gateway_Split" name="Parallel Processing">
<bpmn:incoming>Flow_In</bpmn:incoming>
<bpmn:outgoing>Flow_CreditCheck</bpmn:outgoing>
<bpmn:outgoing>Flow_IncomeVerification</bpmn:outgoing>
<bpmn:outgoing>Flow_DocumentReview</bpmn:outgoing>
</bpmn:parallelGateway>
<!-- All three tasks execute in parallel -->
<bpmn:sequenceFlow id="Flow_CreditCheck" sourceRef="Gateway_Split" targetRef="Task_CreditCheck" />
<bpmn:sequenceFlow id="Flow_IncomeVerification" sourceRef="Gateway_Split" targetRef="Task_VerifyIncome" />
<bpmn:sequenceFlow id="Flow_DocumentReview" sourceRef="Gateway_Split" targetRef="Task_ReviewDocs" />
<!-- Tasks run simultaneously -->
<bpmn:serviceTask id="Task_CreditCheck" name="Credit Bureau Check" />
<bpmn:serviceTask id="Task_VerifyIncome" name="Verify Income" />
<bpmn:userTask id="Task_ReviewDocs" name="Review Documents" />
Join - Wait for All Paths
<!-- Parallel tasks complete -->
<bpmn:sequenceFlow sourceRef="Task_CreditCheck" targetRef="Gateway_Join" />
<bpmn:sequenceFlow sourceRef="Task_VerifyIncome" targetRef="Gateway_Join" />
<bpmn:sequenceFlow sourceRef="Task_ReviewDocs" targetRef="Gateway_Join" />
<!-- Join gateway waits for ALL incoming flows -->
<bpmn:parallelGateway id="Gateway_Join" name="Wait for All">
<bpmn:incoming>Flow_FromCredit</bpmn:incoming>
<bpmn:incoming>Flow_FromIncome</bpmn:incoming>
<bpmn:incoming>Flow_FromDocs</bpmn:incoming>
<bpmn:outgoing>Flow_Continue</bpmn:outgoing>
</bpmn:parallelGateway>
<!-- Process continues only after all tasks complete -->
<bpmn:sequenceFlow id="Flow_Continue" sourceRef="Gateway_Join" targetRef="Task_MakeDecision" />
Complete Parallel Example
<bpmn:process id="ParallelApproval">
<bpmn:startEvent id="Start" />
<bpmn:sequenceFlow sourceRef="Start" targetRef="Gateway_ParallelSplit" />
<!-- Split: Start 3 parallel checks -->
<bpmn:parallelGateway id="Gateway_ParallelSplit" />
<!-- Path 1: Credit Check -->
<bpmn:sequenceFlow sourceRef="Gateway_ParallelSplit" targetRef="Task_CreditCheck" />
<bpmn:serviceTask id="Task_CreditCheck" name="Credit Bureau Check">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Endpoint" value="/api/credit-bureau/check" />
<custom:property name="Method" value="POST" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:serviceTask>
<bpmn:sequenceFlow sourceRef="Task_CreditCheck" targetRef="Gateway_ParallelJoin" />
<!-- Path 2: Income Verification -->
<bpmn:sequenceFlow sourceRef="Gateway_ParallelSplit" targetRef="Task_VerifyIncome" />
<bpmn:serviceTask id="Task_VerifyIncome" name="Verify Income">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Endpoint" value="/api/income/verify" />
<custom:property name="Method" value="POST" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:serviceTask>
<bpmn:sequenceFlow sourceRef="Task_VerifyIncome" targetRef="Gateway_ParallelJoin" />
<!-- Path 3: Fraud Check -->
<bpmn:sequenceFlow sourceRef="Gateway_ParallelSplit" targetRef="Task_FraudCheck" />
<bpmn:serviceTask id="Task_FraudCheck" name="Fraud Screening">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Endpoint" value="/api/fraud/screen" />
<custom:property name="Method" value="POST" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:serviceTask>
<bpmn:sequenceFlow sourceRef="Task_FraudCheck" targetRef="Gateway_ParallelJoin" />
<!-- Join: Wait for all 3 paths -->
<bpmn:parallelGateway id="Gateway_ParallelJoin" />
<bpmn:sequenceFlow sourceRef="Gateway_ParallelJoin" targetRef="Task_Consolidate" />
<!-- Continue after all complete -->
<bpmn:scriptTask id="Task_Consolidate" name="Consolidate Results">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Script" value="
// All three checks are complete - consolidate results
allChecksPassed =
creditCheckPassed &&
incomeVerified &&
!fraudDetected;
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:scriptTask>
<bpmn:sequenceFlow sourceRef="Task_Consolidate" targetRef="End" />
<bpmn:endEvent id="End" />
</bpmn:process>
Inclusive Gateway
Multiple paths can be taken based on conditions.
<bpmn:inclusiveGateway id="Gateway_Notifications" name="Send Notifications">
<bpmn:incoming>Flow_In</bpmn:incoming>
<bpmn:outgoing>Flow_Email</bpmn:outgoing>
<bpmn:outgoing>Flow_SMS</bpmn:outgoing>
<bpmn:outgoing>Flow_Push</bpmn:outgoing>
</bpmn:inclusiveGateway>
<!-- Email flow - always taken -->
<bpmn:sequenceFlow id="Flow_Email" sourceRef="Gateway_Notifications" targetRef="Task_SendEmail">
<bpmn:conditionExpression>true</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<!-- SMS flow - only if phone number exists -->
<bpmn:sequenceFlow id="Flow_SMS" sourceRef="Gateway_Notifications" targetRef="Task_SendSMS">
<bpmn:conditionExpression>customerPhone !== null && customerPhone !== ''</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<!-- Push flow - only if mobile app installed -->
<bpmn:sequenceFlow id="Flow_Push" sourceRef="Gateway_Notifications" targetRef="Task_SendPush">
<bpmn:conditionExpression>hasMobileApp === true</bpmn:conditionExpression>
</bpmn:sequenceFlow>
Gateway Evaluation Order
When a gateway is reached, the engine evaluates conditions in this order:
- Gateway
ConditionProperty: If present, execute the script and use returned flow name - Sequence Flow
conditionExpression: Evaluate each outgoing flow's condition - Default Flow: Take the flow marked as
default - First Flow: If nothing else matches, take the first outgoing flow
Example: Hybrid Approach
<bpmn:exclusiveGateway id="Gateway_Hybrid" default="Flow_Default">
<bpmn:extensionElements>
<custom:properties>
<!-- Try gateway condition first -->
<custom:property name="Condition" value="
// Complex logic using BankLingo commands
const decision = doCmd('GetApprovalDecision', {
customerId, loanAmount, creditScore
});
return decision.flowName; // Returns flow name or null
" />
</custom:properties>
</bpmn:extensionElements>
<bpmn:outgoing>Flow_AutoApprove</bpmn:outgoing>
<bpmn:outgoing>Flow_ManualReview</bpmn:outgoing>
<bpmn:outgoing>Flow_Default</bpmn:outgoing>
</bpmn:exclusiveGateway>
<!-- If gateway condition returns null or fails, evaluate flow conditions -->
<bpmn:sequenceFlow id="Flow_AutoApprove" sourceRef="Gateway_Hybrid" targetRef="Task_AutoApprove">
<bpmn:conditionExpression>creditScore >= 720 && loanAmount < 25000</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_ManualReview" sourceRef="Gateway_Hybrid" targetRef="Task_ManualReview">
<bpmn:conditionExpression>creditScore >= 580</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<!-- If nothing matches, take default -->
<bpmn:sequenceFlow id="Flow_Default" sourceRef="Gateway_Hybrid" targetRef="Task_Reject" />
Use Cases
1. Amount-Based Routing
<bpmn:exclusiveGateway id="Gateway_Amount">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
if (amount < 10000) return 'Flow_Tier1';
if (amount < 50000) return 'Flow_Tier2';
if (amount < 100000) return 'Flow_Tier3';
return 'Flow_BoardApproval';
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:exclusiveGateway>
2. Customer Segment Routing
<bpmn:exclusiveGateway id="Gateway_Segment">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
if (customerSegment === 'VIP') return 'Flow_VIPProcess';
if (customerSegment === 'Premium') return 'Flow_PremiumProcess';
return 'Flow_StandardProcess';
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:exclusiveGateway>
3. Time-Based Routing
<bpmn:exclusiveGateway id="Gateway_Time">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
const hour = new Date().getHours();
const dayOfWeek = new Date().getDay();
// Weekend or after hours
if (dayOfWeek === 0 || dayOfWeek === 6 || hour < 8 || hour >= 17) {
return 'Flow_AfterHours';
}
return 'Flow_BusinessHours';
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:exclusiveGateway>
4. Complex Multi-Factor Decision
<bpmn:exclusiveGateway id="Gateway_ComplexDecision">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
// Score-based routing with multiple factors
let routingScore = 0;
if (creditScore >= 720) routingScore += 40;
else if (creditScore >= 650) routingScore += 20;
else if (creditScore < 580) return 'Flow_Reject';
if (debtToIncomeRatio < 36) routingScore += 30;
else if (debtToIncomeRatio > 43) return 'Flow_Reject';
if (customerTenureYears > 5) routingScore += 15;
if (numberOfAccounts > 3) routingScore += 10;
if (loanAmount > 100000) routingScore -= 20;
// Route based on total score
if (routingScore >= 70) return 'Flow_AutoApprove';
if (routingScore >= 50) return 'Flow_StandardReview';
if (routingScore >= 30) return 'Flow_EnhancedReview';
return 'Flow_SeniorReview';
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:exclusiveGateway>
Best Practices
1. Always Set a Default Flow
<bpmn:exclusiveGateway id="Gateway_1" default="Flow_Default">
This ensures the process never gets stuck if no conditions match.
2. Name Flows Clearly
<bpmn:sequenceFlow id="Flow_HighValue" name="Amount > $50,000" ... />
Use descriptive names that explain the routing logic.
3. Keep Conditions Simple
Move complex logic to script tasks before the gateway:
<!-- Good: Calculate first, then route -->
<bpmn:scriptTask id="Task_Calculate" name="Calculate Routing">
<custom:property name="Script" value="routingDecision = complexCalculation();" />
</bpmn:scriptTask>
<bpmn:exclusiveGateway id="Gateway_Route">
<custom:property name="Condition" value="return routingDecision;" />
</bpmn:exclusiveGateway>
4. Document Gateway Logic
<bpmn:exclusiveGateway id="Gateway_Risk" name="Risk Assessment">
<bpmn:documentation>
Routes applications based on risk score:
- Low Risk (Score >= 70): Auto-approve
- Medium Risk (Score 50-69): Officer review
- High Risk (Score < 50): Manager review
</bpmn:documentation>
</bpmn:exclusiveGateway>
5. Use Meaningful Variable Names
// Good
return creditScore >= 720 ? 'Flow_Approved' : 'Flow_Review';
// Avoid
return cs >= 720 ? 'f1' : 'f2';
Debugging Gateways
Enable execution logging to see gateway decisions:
{
"executionLogs": [
"[GATEWAY] Evaluating exclusive gateway: Gateway_RiskLevel",
"[GATEWAY] Executing gateway condition script",
"[GATEWAY] Condition returned: Flow_MediumRisk",
"[GATEWAY] Taking flow: Flow_MediumRisk → Task_OfficerReview"
]
}
Next Steps
- UserTask - Combine with user decisions
- ScriptTask - Calculate routing logic
- Examples - Complete routing examples
- Execution Modes - Debug gateway decisions