Portal Community

When to Use

Two-phase execution: On first execution the node creates an EngageSession and one InboxItem per resolved actor, then routes to waiting. The workflow instance is durably persisted. When an actor replies through the WorkDesk UI, the engine resumes execution at this node with the reply data in inputData["approvalDecision"] and routes to approved, rejected, or success.

Configuration

FieldRequiredDescription
message Required The message text displayed to the actor in their inbox. Supports BizFirst template substitution using {{variableName}} syntax. Example: "Hi {{firstName}}, please review order {{orderId}} and reply APPROVE or DENY."
actors Optional* Comma-separated list of actor IDs who will receive the chat inbox item. Takes priority over user_id and channel. Example: "user:jane.doe,user:john.smith". At least one of actors, user_id, or channel is required.
user_id Optional* Single target user identifier. Format: user:email@company.com. Used when actors is not set. At least one of actors, user_id, or channel is required.
channel Optional* Target channel identifier. Used as fallback when both actors and user_id are absent. Example: "payroll-approvals". At least one of actors, user_id, or channel is required.
context Optional Additional context text attached to the pending inbox item. Displayed below the message for the actor. Useful for supplementary reference data without cluttering the main message.
timeout_minutes Optional Integer minutes before the waiting session expires. When the session expires the EngageSession onTimeout policy fires (defaults to "rejected"), resuming the workflow. Set to 0 or omit for unlimited wait. Must be >= 0.
Actor resolution priority: The node resolves actor IDs in this order: actors (comma-separated list) → user_idchannel. If all three are absent, the node routes to the error port immediately in Phase 1 without sending any message.

Sample Configuration

{
  "message": "Hi {{requesterName}}, your expense claim for {{currency}}{{amount}} requires manager sign-off. Reply APPROVE to proceed or DENY to return for revision.",
  "actors": "user:finance.manager@company.com",
  "context": "Claim ID: {{claimId}} | Submitted: {{submittedAt}} | Category: {{expenseCategory}}",
  "timeout_minutes": 1440
}

The workflow suspends for up to 24 hours (1440 minutes). The {{…}} tokens are resolved at runtime from the workflow data context before the message is sent to the actor's inbox.

Validation Errors

Error MessageCause & Fix
message is required The message field is empty or missing. Provide a non-blank string.
At least one of actors, user_id, or channel is required No actor target is configured. Set actors, user_id, or channel.
timeout_minutes must be >= 0 timeout_minutes was set to a negative integer. Use 0 for unlimited or any positive integer.
No actors configured for chat node. Set actors, user_id, or channel. Runtime validation found all actor fields empty after config is loaded. A {{variable}} expression may have resolved to an empty string at runtime.

Output

Waiting Port (waiting)

Fired during Phase 1. The workflow is suspended and durably persisted. Output contains session tracking data for observability.

FieldTypeDescription
engage.session_idintegerInternal EngageSession ID created by the ProcessEngage infrastructure. Used by the resume endpoint to look up this suspended execution.
engage.actor_countintegerNumber of actors who received an InboxItem. Useful for audit logging in downstream observer nodes.

Approved Port (approved)

Fired during Phase 2 when IChatReplyParser classifies the reply as an approval. Default approval keyword: "approved" (exact decision value from the resume envelope).

FieldTypeDescription
approvalDecisionobjectFull approval decision envelope from the ProcessEngage resume callback, containing decision, actorId, decidedAt, and additionalData.
reply_textstringRaw reply text typed by the actor (extracted from additionalData.reply_text).
decisionstring"approved"

Rejected Port (rejected)

Fired during Phase 2 when the reply is classified as a rejection, or when the session expires and the onTimeout policy resolves to "rejected".

FieldTypeDescription
approvalDecisionobjectFull approval decision envelope.
reply_textstringRaw reply text typed by the actor, or empty string on timeout.
decisionstring"rejected"

Success Port (success)

Fallback port for Phase 2. Fires when a reply is received but does not match the approved or rejected classification — for example a free-text comment, an abstention, or an unrecognised keyword. Also fires when the IChatReplyParser is not registered and the raw decision is "unknown".

FieldTypeDescription
approvalDecisionobjectFull approval decision envelope.
reply_textstringRaw reply text typed by the actor.
decisionstring"unknown" or "abstained"

Error Port (error)

Fires during Phase 1 if configuration is invalid (missing message or no actors) or if EngageSession creation fails at the infrastructure level. Session timeout routing is controlled by the EngageSession onTimeout policy, not the error port.

FieldTypeDescription
errorstringHuman-readable description of the configuration or infrastructure error.

Sample Output

// Phase 1 — Waiting port
{
  "engage.session_id": 4721,
  "engage.actor_count": 2
}

// Phase 2 — Approved port
{
  "approvalDecision": {
    "decision": "approved",
    "actorId": "user:jane.doe@company.com",
    "decidedAt": "2026-03-15T14:32:00Z",
    "additionalData": {
      "reply_text": "APPROVE — all figures look correct, proceed."
    }
  },
  "reply_text": "APPROVE — all figures look correct, proceed.",
  "decision": "approved"
}

// Phase 2 — Rejected port
{
  "approvalDecision": {
    "decision": "rejected",
    "actorId": "user:jane.doe@company.com",
    "decidedAt": "2026-03-15T14:45:00Z",
    "additionalData": {
      "reply_text": "DENY — invoiced amount does not match PO line."
    }
  },
  "reply_text": "DENY — invoiced amount does not match PO line.",
  "decision": "rejected"
}

Expression Reference

On Phase 2 ports, reference output fields in downstream nodes using the workflow node key:

ExpressionValue
{{ $output.chatNode.decision }}Routing decision string: "approved", "rejected", or "unknown"
{{ $output.chatNode.reply_text }}Raw reply text typed by the actor
{{ $output.chatNode.approvalDecision.actorId }}Actor ID of the person who replied
{{ $output.chatNode.approvalDecision.decidedAt }}ISO 8601 timestamp of the reply
{{ $output.chatNode["engage.session_id"] }}EngageSession ID (available on the waiting port)
{{ $output.chatNode["engage.actor_count"] }}Number of actors notified (available on the waiting port)
Node key: Replace chatNode with the actual key assigned to this node in the workflow designer (set in the node properties panel). Expression paths are case-sensitive.

Node Policies & GuardRails

Examples

Example 1 — Payroll Exception Approval

A payroll processing workflow detects an anomaly (employee hours exceed the 60-hour weekly cap). It pauses and asks the payroll manager to confirm before processing the run.

{
  "message": "Payroll anomaly detected for {{employeeName}} (ID: {{employeeId}}). Hours reported: {{hoursWorked}} hrs. This exceeds the 60-hour weekly cap. Reply APPROVE to process as-is, or DENY to hold for manual correction.",
  "actors": "user:payroll.manager@company.com",
  "context": "Pay Period: {{payPeriod}} | Department: {{department}} | Baseline Hours: {{normalHours}}",
  "timeout_minutes": 480
}

The approved port connects to the payroll processing step. The rejected port connects to a correction task node that reassigns the timesheet. The 8-hour timeout ensures the workflow does not miss the payroll run window — if the manager does not reply, the session expires and routes through the error port to an escalation notification.

Example 2 — Multi-Actor Fraud Review

A fraud detection sub-workflow flags a high-value transaction and sends the alert to two risk analysts simultaneously. The first to respond wins via the FirstResponse strategy.

{
  "message": "FRAUD ALERT — Transaction {{transactionId}} for {{currency}}{{amount}} to account {{recipientAccount}} flagged by risk model (score: {{riskScore}}/100). Reply CLEAR to release funds or HOLD to freeze the transaction.",
  "actors": "user:risk.analyst.a@company.com,user:risk.analyst.b@company.com",
  "context": "Customer: {{customerName}} | Account Age: {{accountAgeDays}} days | Transaction Location: {{transactionLocation}} | Previous Flags: {{previousFlagCount}}",
  "timeout_minutes": 60
}

Both analysts receive an InboxItem simultaneously. The first reply wins; remaining items are closed. The 60-minute timeout connects to a fraud freeze escalation sub-workflow via the error port — ensuring that if neither analyst responds, the transaction is automatically frozen as a safety measure.

Example 3 — Infrastructure Change Approval (CAB Gate)

A deployment pipeline pauses at a Chat node to collect explicit CAB Chair sign-off before applying schema migrations to the production database.

{
  "message": "CAB APPROVAL REQUIRED — Change {{changeId}}: {{changeTitle}}. Planned execution window: {{executionWindow}}. This change will modify {{affectedTableCount}} database tables in {{environmentName}}. Reply APPROVE to allow deployment, or ROLLBACK to abort and revert the pipeline.",
  "user_id": "user:cab.chair@company.com",
  "context": "Risk Rating: {{riskRating}} | Rollback Plan: {{rollbackPlan}} | Requested By: {{requestedBy}} | Peer Review: {{peerReviewUrl}}",
  "timeout_minutes": 120
}

Uses user_id (single actor) since the CAB Chair is the designated approver. The approved port proceeds to apply migrations. The rejected port triggers the pipeline abort sequence. The success port (non-matching reply) connects to a clarification step that sends a follow-up message and waits again. The 2-hour timeout prevents the deployment window from being missed.