Receive Task - Wait for External Signals
Receive Task pauses process execution until an external signal or message is received. It's essential for integrating with external systems, webhooks, and asynchronous operations.
Overview
A Receive Task allows processes to:
- ✅ Wait for external events (webhooks, callbacks, messages)
- ✅ Integrate with external systems asynchronously
- ✅ Resume automatically when signal received (Phase 3)
- ✅ Timeout with boundaries (Phase 4)
- ✅ Correlate messages with correlation keys
Properties
Required Properties
| Property | Type | Required | Description |
|---|---|---|---|
TaskType | string | Yes | Must be "ReceiveTask" |
Name | string | Yes | Display name |
message | string | No | Expected message name |
Optional Properties
| Property | Type | Default | Description |
|---|---|---|---|
correlationKey | string | instanceId | Key to match incoming signal |
resultVariable | string | lastSignalData | Variable to store signal data |
outputMapping | JSON | null | Map signal data to context |
timeout | duration | none | Maximum wait time (Phase 4) |
Basic Receive Task
Simple Wait for Signal
<bpmn:receiveTask id="WaitForApproval"
name="Wait for Manager Approval"
messageRef="ManagerApprovalMessage">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="ManagerApproval"/>
<custom:property name="resultVariable" value="approvalData"/>
<custom:property name="correlationKey" value="context.requestId"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Message definition -->
<bpmn:message id="ManagerApprovalMessage" name="ManagerApproval"/>
How it works:
- Process reaches Receive Task
- Process pauses and waits
- Status:
Waiting, waiting for:ManagerApprovalmessage - External system sends signal via API
- Process resumes automatically
- Signal data available in
context.approvalData
Signaling a Receive Task
From External System (API)
Implementation details removed for security.
Contact support for implementation guidance.
From Another Process
// In another process, signal this process
BankLingo.ExecuteCommand('SignalProcess', {
instanceId: 'PROCESS-12345',
taskId: 'WaitForApproval',
signalData: {
approved: true,
approver: 'system',
comments: 'Auto-approved'
}
});
Correlation Keys
Use correlation keys to match signals to the correct process instance:
Setting Correlation Key
<bpmn:receiveTask id="WaitForPayment"
name="Wait for Payment Confirmation">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="PaymentConfirmation"/>
<custom:property name="correlationKey" value="context.transactionId"/>
<custom:property name="resultVariable" value="paymentResult"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
Sending Signal with Correlation Key
Implementation details removed for security.
Contact support for implementation guidance.
Use Cases for Correlation Keys:
- Payment gateway webhooks (use transaction ID)
- External order tracking (use order number)
- Partner API callbacks (use reference ID)
- Multiple instances of same process (unique correlation per instance)
Output Mapping
Extract specific fields from signal data:
<bpmn:receiveTask id="WaitForAPIResponse"
name="Wait for API Response">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="APIResponse"/>
<custom:property name="outputMapping" value="{
"customerId": "signal.data.customer.id",
"customerName": "signal.data.customer.name",
"accountStatus": "signal.data.account.status",
"creditLimit": "signal.data.account.creditLimit"
}"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
Signal data structure:
{
"data": {
"customer": {
"id": "CUST-123",
"name": "John Doe"
},
"account": {
"status": "ACTIVE",
"creditLimit": 10000
}
}
}
Result in context:
context.customerId // "CUST-123"
context.customerName // "John Doe"
context.accountStatus // "ACTIVE"
context.creditLimit // 10000
Timeout Handling (Phase 4)
Add timeout boundary events to prevent indefinite waiting:
<bpmn:receiveTask id="WaitForPartnerResponse"
name="Wait for Partner API Response">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="PartnerAPIResponse"/>
<custom:property name="correlationKey" value="context.apiRequestId"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Timeout after 30 minutes -->
<bpmn:boundaryEvent id="ResponseTimeout"
name="30 Min Timeout"
attachedToRef="WaitForPartnerResponse"
cancelActivity="true">
<bpmn:timerEventDefinition>
<bpmn:timeDuration>PT30M</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
<!-- Handle timeout -->
<bpmn:scriptTask id="HandleTimeout" name="Handle Timeout">
<bpmn:script>
logger.error('Partner API response timeout after 30 minutes');
context.apiStatus = 'TIMEOUT';
context.errorMessage = 'Partner did not respond within 30 minutes';
// Retry logic or fallback
if (context.retryCount < 3) {
context.retryCount = (context.retryCount || 0) + 1;
// Flow back to retry
} else {
// Flow to error handling
throw new BpmnError('API_TIMEOUT', 'Max retries exceeded');
}
</bpmn:script>
</bpmn:scriptTask>
Common Patterns
Pattern 1: Payment Gateway Integration
<bpmn:process id="PaymentProcess" name="Payment Processing">
<!-- Initiate payment -->
<bpmn:scriptTask id="InitiatePayment" name="Initiate Payment">
<bpmn:script>
// Call payment gateway
var result = BankLingo.ExecuteCommand('InitiatePayment', {
amount: context.amount,
customerId: context.customerId,
callbackUrl: 'https://api.bank.com/payments/callback'
});
context.paymentId = result.paymentId;
context.paymentStatus = 'PENDING';
logger.info('Payment initiated: ' + context.paymentId);
</bpmn:script>
</bpmn:scriptTask>
<!-- Wait for payment gateway callback -->
<bpmn:receiveTask id="WaitForPaymentCallback"
name="Wait for Payment Confirmation">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="PaymentCallback"/>
<custom:property name="correlationKey" value="context.paymentId"/>
<custom:property name="outputMapping" value="{
"paymentStatus": "signal.status",
"transactionId": "signal.transactionId",
"paidAmount": "signal.amount"
}"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Timeout after 5 minutes -->
<bpmn:boundaryEvent id="PaymentTimeout"
attachedToRef="WaitForPaymentCallback">
<bpmn:timerEventDefinition>
<bpmn:timeDuration>PT5M</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
<!-- Check payment status -->
<bpmn:exclusiveGateway id="CheckPayment" name="Payment Status?"/>
<bpmn:scriptTask id="PaymentSuccess" name="Payment Success">
<bpmn:script>
logger.info('Payment successful: ' + context.transactionId);
context.finalStatus = 'COMPLETED';
</bpmn:script>
</bpmn:scriptTask>
<bpmn:scriptTask id="PaymentFailed" name="Payment Failed">
<bpmn:script>
logger.error('Payment failed: ' + context.paymentStatus);
context.finalStatus = 'FAILED';
throw new BpmnError('PAYMENT_FAILED', 'Payment was not successful');
</bpmn:script>
</bpmn:scriptTask>
</bpmn:process>
External Webhook Handler:
Implementation details removed for security.
Contact support for implementation guidance.
Pattern 2: External Approval System
<bpmn:process id="ExternalApprovalProcess" name="External Approval">
<!-- Send approval request to external system -->
<bpmn:scriptTask id="SendApprovalRequest" name="Send to External System">
<bpmn:script>
var result = BankLingo.ExecuteCommand('SendExternalApprovalRequest', {
requestType: 'LOAN_APPROVAL',
requestData: {
applicantId: context.applicantId,
loanAmount: context.loanAmount,
requestId: context.requestId
},
callbackUrl: 'https://api.bank.com/approvals/callback'
});
context.externalRequestId = result.requestId;
logger.info('Approval request sent: ' + result.requestId);
</bpmn:script>
</bpmn:scriptTask>
<!-- Wait for external approval -->
<bpmn:receiveTask id="WaitForExternalApproval"
name="Wait for External Approval">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="ExternalApproval"/>
<custom:property name="correlationKey" value="context.externalRequestId"/>
<custom:property name="resultVariable" value="approvalResponse"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Timeout after 24 hours -->
<bpmn:boundaryEvent id="ApprovalTimeout"
attachedToRef="WaitForExternalApproval">
<bpmn:timerEventDefinition>
<bpmn:timeDuration>P1D</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
<!-- Process approval response -->
<bpmn:scriptTask id="ProcessApproval" name="Process Approval">
<bpmn:script>
var response = context.approvalResponse;
context.approvalStatus = response.status;
context.approvedBy = response.approver;
context.approvalDate = response.timestamp;
context.comments = response.comments;
logger.info('Approval received: ' + response.status);
</bpmn:script>
</bpmn:scriptTask>
</bpmn:process>
Pattern 3: Multi-Stage External Process
<!-- Wait for multiple external signals in sequence -->
<bpmn:process id="MultiStageExternal" name="Multi-Stage External">
<!-- Stage 1: Identity Verification -->
<bpmn:scriptTask id="RequestIdentity" name="Request Identity Verification">
<bpmn:script>
BankLingo.ExecuteCommand('RequestIdentityVerification', {
customerId: context.customerId,
verificationType: 'FULL'
});
context.identityRequestId = 'ID-' + Date.now();
</bpmn:script>
</bpmn:scriptTask>
<bpmn:receiveTask id="WaitForIdentity" name="Wait for Identity Result">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="IdentityVerified"/>
<custom:property name="correlationKey" value="context.identityRequestId"/>
<custom:property name="outputMapping" value="{
"identityVerified": "signal.verified",
"identityScore": "signal.score"
}"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Stage 2: Credit Check -->
<bpmn:scriptTask id="RequestCreditCheck" name="Request Credit Check">
<bpmn:script>
BankLingo.ExecuteCommand('RequestCreditCheck', {
customerId: context.customerId
});
context.creditRequestId = 'CR-' + Date.now();
</bpmn:script>
</bpmn:scriptTask>
<bpmn:receiveTask id="WaitForCredit" name="Wait for Credit Result">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="CreditCheckComplete"/>
<custom:property name="correlationKey" value="context.creditRequestId"/>
<custom:property name="outputMapping" value="{
"creditScore": "signal.score",
"creditRating": "signal.rating"
}"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Stage 3: Background Check -->
<bpmn:scriptTask id="RequestBackground" name="Request Background Check">
<bpmn:script>
BankLingo.ExecuteCommand('RequestBackgroundCheck', {
customerId: context.customerId
});
context.backgroundRequestId = 'BG-' + Date.now();
</bpmn:script>
</bpmn:scriptTask>
<bpmn:receiveTask id="WaitForBackground" name="Wait for Background Result">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="BackgroundCheckComplete"/>
<custom:property name="correlationKey" value="context.backgroundRequestId"/>
<custom:property name="outputMapping" value="{
"backgroundCleared": "signal.cleared",
"backgroundRemarks": "signal.remarks"
}"/>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Aggregate all results -->
<bpmn:scriptTask id="AggregateResults" name="Aggregate Results">
<bpmn:script>
var allPassed = context.identityVerified &&
context.creditScore >= 650 &&
context.backgroundCleared;
context.verificationStatus = allPassed ? 'APPROVED' : 'REJECTED';
logger.info('Verification complete: ' + context.verificationStatus);
</bpmn:script>
</bpmn:scriptTask>
</bpmn:process>
Callback Mechanism (Phase 3)
Receive Tasks use the callback system for automatic resumption:
Database Entry
-- CallbackRegistry table
INSERT INTO CallbackRegistry (
ProcessInstanceId, -- "PROCESS-12345"
CallbackType, -- "External"
Message, -- "PaymentCallback"
CorrelationKey, -- "PAY-789"
ParentTaskId, -- "WaitForPaymentCallback"
Status -- "Pending"
)
Process State
Implementation details removed for security.
Contact support for implementation guidance.
Automatic Resumption
When signal received:
- Match by
correlationKeyorinstanceId - Find process in
CallbackRegistry - Update process state with signal data
- Resume execution from Receive Task
- Continue to next task
Error Handling (Phase 5)
Handle signal errors or missing data:
<bpmn:receiveTask id="WaitForData" name="Wait for External Data">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="message" value="ExternalData"/>
<custom:property name="validateScript"><![CDATA[
// Validate received signal data
var signal = context._lastSignal;
if (!signal.data) {
throw new BpmnError('INVALID_SIGNAL', 'Signal data is missing');
}
if (!signal.data.customerId) {
throw new BpmnError('INVALID_SIGNAL', 'Customer ID is required');
}
if (signal.data.amount <= 0) {
throw new BpmnError('INVALID_SIGNAL', 'Invalid amount: ' + signal.data.amount);
}
return true;
]]></custom:property>
</custom:properties>
</bpmn:extensionElements>
</bpmn:receiveTask>
<!-- Catch validation errors -->
<bpmn:boundaryEvent id="InvalidSignal"
attachedToRef="WaitForData"
cancelActivity="true">
<bpmn:errorEventDefinition errorRef="ValidationError" />
</bpmn:boundaryEvent>
<bpmn:scriptTask id="HandleInvalidSignal" name="Handle Invalid Signal">
<bpmn:script>
var error = context._lastError;
logger.error('Invalid signal received: ' + error.errorMessage);
// Request resend or alert
BankLingo.ExecuteCommand('AlertInvalidSignal', {
instanceId: context._instanceId,
errorMessage: error.errorMessage
});
</bpmn:script>
</bpmn:scriptTask>
Best Practices
✅ Do This
<!-- ✅ Use correlation keys for webhooks -->
<custom:property name="correlationKey" value="context.transactionId"/>
<!-- ✅ Add timeouts to prevent hanging -->
<bpmn:boundaryEvent id="Timeout" attachedToRef="WaitForSignal">
<bpmn:timerEventDefinition>
<bpmn:timeDuration>PT30M</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
<!-- ✅ Use output mapping to extract specific fields -->
<custom:property name="outputMapping" value="{...}"/>
<!-- ✅ Validate signal data -->
<custom:property name="validateScript" value="..."/>
⌠Don't Do This
<!-- ⌠No timeout (process hangs indefinitely) -->
<bpmn:receiveTask id="Wait" name="Wait Forever">
<!-- Missing timeout boundary -->
</bpmn:receiveTask>
<!-- ⌠No correlation key for external systems -->
<bpmn:receiveTask id="WaitWebhook" name="Wait for Webhook">
<!-- Missing correlationKey - hard to match -->
</bpmn:receiveTask>
<!-- ⌠No validation (accepts any data) -->
<bpmn:receiveTask id="WaitData" name="Wait for Data">
<!-- Missing validateScript - unsafe -->
</bpmn:receiveTask>
Related Documentation
- Callbacks Overview - Callback mechanism details
- Timer Events - Timeout boundaries
- Error Handling - Signal validation
- Send Task - Sending messages
- Call Activity - Subprocess callbacks
Features Used:
- Core: Receive Task
- Phase 3: Callbacks
- Phase 4: Timer Events (timeouts)
- Phase 5: Error Handling
Status: ✅ Production Ready
Version: 2.0
Last Updated: January 2026