Form node type: form
A two-phase Human-in-the-Loop node that renders an Atlas Form (or inline JSON schema form) to a designated actor via the BizFirst WorkDesk inbox, suspends the workflow, and resumes with the submitted form data when the actor completes the form.
When to Use
- Invoice data entry and approval: A mid-workflow form pauses an accounts-payable workflow, presenting a structured invoice entry form to the AP clerk. Submitted data — supplier name, invoice number, amount, and GL code — flows to the downstream payment processing step.
- Employee onboarding information collection: An HR onboarding workflow uses a Form node to collect personal details, emergency contacts, and tax information from the new employee before provisioning accounts and benefits.
- Expense claim submission: A pre-populated expense form is rendered to the employee with fields for amount, category, date, and receipt upload. Submitted data routes to the approval step automatically.
- Incident report filing: An IT operations workflow pauses at a Form node to have the engineer-on-call complete a structured incident report with severity classification, affected systems, and remediation steps before closing the alert.
- Structured change request intake: A change management workflow presents a change request form to the requestor mid-flow. Required fields enforce that risk assessment, rollback plan, and test evidence are captured before the CAB review step.
pending port. When the actor submits the form, the engine resumes at this node with the submitted field values in inputData["approvalDecision"].additionalData and routes to success.
Configuration
| Field | Required | Description |
|---|---|---|
form_schema |
Required | Either an integer Atlas FormID (e.g. 13005) or an inline JSON schema object defining the form fields. When an integer is provided, the WorkDesk renders the pre-configured Atlas form with that ID. When a JSON object is provided, it must contain a fields array. See sample configuration below. |
assigned_to |
Required | User ID or role identifier who must complete the form. Format: user:email@company.com or role:payroll-manager. Only one actor is supported per Form node — for multi-actor scenarios use parallel branches each with their own Form node. |
title |
Optional | Display title shown in the WorkDesk inbox item and above the form. Defaults to the node key if omitted. Supports BizFirst template expressions, e.g. "Invoice Review — {{supplierName}}". |
description |
Optional | Instructional text displayed to the actor above the form fields. Use this to provide context, reference numbers, or instructions specific to this workflow step. |
due_at |
Optional | ISO 8601 deadline timestamp for form completion. Example: "2026-04-01T09:00:00Z". When the deadline passes the EngageSession expires and the workflow can be resumed via the error-handling path. Does not auto-route — wire the error port to handle expired sessions. |
form_schema of a node while workflow instances are suspended waiting for that form to be submitted. In-flight instances hold a reference to the schema at the time of suspension. Changing the schema mid-flight will corrupt submitted data mapping. Always version your Atlas Forms and bump the FormID, or deploy schema changes only after all in-flight instances have completed.
Sample Configuration
Option A — Atlas FormID (recommended for production)
{
"form_schema": 13005,
"assigned_to": "role:accounts-payable",
"title": "Invoice Review — {{supplierName}}",
"description": "Please verify the invoice details below and complete all required fields before submitting. Reference PO: {{purchaseOrderId}}.",
"due_at": "{{invoiceDueDate}}"
}
Using an integer as form_schema references Atlas Form ID 13005. The WorkDesk renders the pre-configured form including any field labels, validation rules, conditional visibility, and styling defined in the Atlas form designer.
Option B — Inline JSON Schema
{
"form_schema": {
"fields": [
{ "name": "supplierName", "type": "text", "label": "Supplier Name", "required": true },
{ "name": "invoiceNumber", "type": "text", "label": "Invoice Number", "required": true },
{ "name": "invoiceAmount", "type": "number", "label": "Amount (USD)", "required": true },
{ "name": "invoiceDate", "type": "date", "label": "Invoice Date", "required": true },
{ "name": "glCode", "type": "text", "label": "GL Code", "required": true },
{ "name": "approvalNotes", "type": "textarea", "label": "Approval Notes", "required": false }
]
},
"assigned_to": "user:ap.reviewer@company.com",
"title": "Invoice Entry Form",
"description": "Enter all invoice details. GL Code must match an approved cost centre.",
"due_at": "2026-06-30T17:00:00Z"
}
Use inline schema for ad-hoc forms or when an Atlas FormID has not yet been created. Field types: text, textarea, number, date, boolean, select.
Validation Errors
| Error Message | Cause & Fix |
|---|---|
Form schema is required |
The form_schema field is missing or resolves to empty/null. Provide a valid Atlas FormID integer or an inline JSON schema object with a fields array. |
AssignedTo (user or role) is required |
The assigned_to field is missing or blank. Provide a user identifier (user:email@company.com) or a role identifier (role:roleName). |
| Error port fires on Phase 1 | EngageSession or InboxItem creation failed at the infrastructure level. Check ProcessEngage service health and database connectivity. The error payload will contain the exception message. |
Output
Pending Port (pending)
Fired during Phase 1. The workflow is suspended and the form is available in the actor's WorkDesk inbox. Output contains session and assignment data for observability.
| Field | Type | Description |
|---|---|---|
engage.session_id | integer | Internal EngageSession ID. Used by the ProcessEngage resume endpoint to locate this suspended execution when the actor submits the form. |
assigned_to | string | The resolved actor ID that received the form InboxItem. Echoes the assigned_to config value. |
Success Port (success)
Fired during Phase 2 when the actor submits the form. All submitted field values are available under formData.
| Field | Type | Description |
|---|---|---|
formData | object | Key-value map of submitted field names to their submitted values. Field names match the name properties defined in the form schema. |
submittedByUserID | string | Actor ID of the person who submitted the form (from the approvalDecision.actorId in the resume envelope). |
submittedAt | string | ISO 8601 timestamp of form submission (from approvalDecision.decidedAt). |
Error Port (error)
Fires during Phase 1 if configuration validation fails or if the ProcessEngage infrastructure call fails. Wire this port to a notification or retry node.
| Field | Type | Description |
|---|---|---|
error | string | Human-readable error description from the configuration validator or infrastructure layer. |
Sample Output
// Phase 1 — Pending port
{
"engage.session_id": 5830,
"assigned_to": "user:ap.reviewer@company.com"
}
// Phase 2 — Success port
{
"formData": {
"supplierName": "Acme Corporation",
"invoiceNumber": "INV-2026-00451",
"invoiceAmount": "4500.00",
"invoiceDate": "2026-05-10",
"glCode": "5200-OPEX",
"approvalNotes": "Standard monthly maintenance invoice. Verified against PO-8812."
},
"submittedByUserID": "user:ap.reviewer@company.com",
"submittedAt": "2026-05-26T11:04:31Z"
}
Expression Reference
Reference submitted form fields in downstream nodes using the workflow node key:
| Expression | Value |
|---|---|
{{ $output.formNode.formData.supplierName }} | Value of the supplierName field submitted by the actor |
{{ $output.formNode.formData.invoiceAmount }} | Value of the invoiceAmount field (string — cast to number as needed) |
{{ $output.formNode.formData.glCode }} | Value of the glCode field |
{{ $output.formNode.submittedByUserID }} | Actor ID of the person who submitted the form |
{{ $output.formNode.submittedAt }} | ISO 8601 timestamp of form submission |
{{ $output.formNode["engage.session_id"] }} | EngageSession ID (available on the pending port) |
formNode with the actual key assigned to this node in the workflow designer. All submitted field values are nested under formData. Field names match the name property from your schema definition exactly, including case.
Node Policies & GuardRails
- Schema validation before save: The WorkDesk enforces the form schema's
requiredfield constraints before allowing submission. Required fields that are blank prevent submission, protecting downstream nodes from missing data. - Field-level data type enforcement: The Atlas form renderer validates field types (number, date, text length) on the client before submission. Downstream nodes can trust that
numberfields contain parseable numeric strings. - Never change in-flight form schemas: Do not modify the
form_schema(or the Atlas form definition) while workflow instances are suspended awaiting submission. In-flight instances hold the schema version at suspension time. Coordinate schema changes with a maintenance window or use Atlas form versioning. - Durable suspension: The workflow state is persisted at the moment the
pendingport fires. A ProcessEngine restart will not lose the pending assignment — the actor's WorkDesk inbox item remains active and submitting it will correctly resume the workflow. - Audit trail of submissions: Every form submission is recorded in the ProcessEngage EngageSession and PendingForm records with actor ID, submission timestamp, and full field data. Do not alter these records — they are the audit trail for regulatory and compliance purposes.
- Single actor per node: The Form node supports exactly one actor per instance (
assigned_toresolves to one user or role). For multi-actor collection (e.g. two approvers must each fill a form), use parallel branches each with their own Form node, then join with a ParallelJoin node. - Deadline expiry: Set
due_atin production workflows so forms do not wait indefinitely. Handle the session expiry by connecting theerrorport to a re-assignment or escalation sub-workflow. - IPendingFormService optional: If
IPendingFormServiceis not registered in the DI container, the WorkDesk form inbox will not populate (the actor will not see the form in their inbox). Always register this service in production deployments.
Examples
Example 1 — Mid-Workflow Invoice Approval
An accounts-payable workflow receives a scanned invoice via email trigger, performs OCR extraction, and then pauses at a Form node for an AP reviewer to verify and correct the extracted data before routing to the payment step.
{
"form_schema": 13005,
"assigned_to": "role:accounts-payable",
"title": "Invoice Verification — {{supplierName}}",
"description": "OCR extracted the following details from the scanned invoice. Please verify each field and correct any errors before submitting. The values below have been pre-populated from the scan.",
"due_at": "{{nextBusinessDayAt5pm}}"
}
Atlas Form 13005 is the standard AP invoice verification form with supplier lookup, GL code validation against the chart of accounts, and a duplicate invoice check. The due_at expression resolves to next business day at 5 PM from the workflow data context. On submission, the formData values flow directly to the payment processing API node.
Example 2 — Employee Onboarding Data Collection
An HR onboarding workflow triggers on a new hire record creation in HRMS. A Form node collects supplementary data that is not in the HRMS system: emergency contacts, preferred name, equipment preferences, and parking permit request.
{
"form_schema": {
"fields": [
{ "name": "preferredName", "type": "text", "label": "Preferred Name", "required": false },
{ "name": "emergencyContact", "type": "text", "label": "Emergency Contact Name", "required": true },
{ "name": "emergencyPhone", "type": "text", "label": "Emergency Contact Phone", "required": true },
{ "name": "equipmentPreference","type": "select", "label": "Equipment Preference", "required": true,
"options": ["Mac (Apple Silicon)", "Windows Laptop", "No Preference"] },
{ "name": "parkingRequired", "type": "boolean", "label": "Parking Permit Required", "required": false },
{ "name": "startDateConfirm", "type": "date", "label": "Confirmed Start Date", "required": true }
]
},
"assigned_to": "user:{{newEmployeeEmail}}",
"title": "Welcome to {{companyName}} — Please Complete Your Onboarding Form",
"description": "Please complete the form below before your start date. All required fields must be filled in. If you have any questions contact HR at hr@company.com.",
"due_at": "{{startDateMinus2Days}}"
}
The assigned_to expression dynamically resolves to the new employee's email from the HRMS trigger data. The form is sent directly to the new hire's inbox before they arrive. Submitted data feeds a parallel branch that provisions equipment via the IT ServiceDesk API and registers the parking permit request.
Example 3 — Incident Report Filing
An IT monitoring workflow detects a P1 incident (service outage). After automated diagnostics run, a Form node pauses the workflow for the engineer-on-call to file a structured incident report before the ticket is escalated to the customer.
{
"form_schema": 13007,
"assigned_to": "user:{{oncallEngineerEmail}}",
"title": "P1 Incident Report — {{serviceName}} Outage",
"description": "A P1 incident has been detected on {{serviceName}} at {{detectedAt}}. Please complete this report within 30 minutes. Automated diagnostics are attached below for reference.",
"due_at": "{{detectedAtPlus30Minutes}}"
}
Atlas Form 13007 is the standard P1 incident report form with fields for root cause classification, affected user count, remediation steps taken, and customer communication status. The 30-minute deadline enforces SLA compliance. On submission, the formData.rootCauseClassification value is used by a downstream Switch node to route the ticket to the correct post-incident review board.