Workflow lifecycle action
Fires when the workflow framework records a meaningful workflow action - a work item assigned, a document submitted, approved, rejected, delegated, escalated, returned, recalled, or completed, or a workflow failure. The workflow framework writes one WorkflowTrackingTable row per action; this event publishes the reportable ones with the workflow, document, step, acting user, new assignee and comment, so approval dashboards, Teams notifications, or downstream systems can follow approvals as they happen instead of polling workflow history. It fires for every workflow type and every company.
| Event class | MGCLatticeWorkflowLifecycleBusinessEvent |
| Contract class | MGCLatticeWorkflowLifecycleBusinessEventContract |
| Category | System administration |
| Module | ModuleAxapta::SystemAdministration |
| Label IDs | WorkflowLifecycleBusinessEventName / WorkflowLifecycleBusinessEventDescription |
| Trigger | WorkflowTrackingCommentTable.insert() -> the tracking row of the recorded action has a reportable TrackingType |
Trigger / Hook
-
Extension class:
MGCLatticeWorkflowTrackingCommentTable_Table_Extension, decorated with[ExtensionOf(tableStr(WorkflowTrackingCommentTable))]. -
CoC method signature:
public void insert(). -
Why a table hook: the workflow framework records every action through
WorkflowTrackingTable::saveTracking(), and there's no public process method that covers all actions. For every action,saveTracking()writes the tracking row, then the work item link (WorkflowTrackingWorkItem), then the comment row, so the event is raised when the comment row is written and can carry the new assignee and the comment. The workflow maintenance job and the unrecoverable-workflow cancel also write comment rows, but only for cancellations, which aren't reported. -
Firing condition: after
next insert(), the activation check runs first; then the tracking row named bythis.WorkflowTrackingTableis read, and the event sends whenMGCLatticeWorkflowLifecycleBusinessEvent::isReportableAction(trackingTable.TrackingType)is true. Reportable tracking types, and theactionvalue each produces:WorkflowTrackingTypeactionCreation Assigned Submission Submitted Approval Approved Rejection Rejected Delegation, AutomaticDelegation, Reassign Delegated EscalationAction, FinalEscalationAction Escalated Completion Completed Fault, Unrecoverable Failed Denied Denied Return Returned RequestChange ChangeRequested Resubmission Resubmitted Recalled Recalled All other tracking types - condition evaluations, activation, cancellation, due-date and duration notices, sub-workflow bookkeeping, and so on - are ignored.
-
One emission per tracking row: an action recorded for several work items or users (for example a step assigned to multiple approvers) produces one event per row. The hook covers every tracking context, including sub-workflows and line-item workflows.
-
Timing:
saveTracking()writes the rows inside its ownttsbegin/ttscommit, sosend()writes to the business events commit log inside that transaction and the event is delivered only if it commits. -
Enablement gate:
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeWorkflowLifecycleBusinessEvent)), checked before the tracking row is read, so while the event isn't activated a comment row costs nothing more.
public void insert()
{
next insert();
if (this.WorkflowTrackingTable
&& BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeWorkflowLifecycleBusinessEvent)))
{
WorkflowTrackingTable trackingTable;
select firstonly trackingTable
where trackingTable.RecId == this.WorkflowTrackingTable;
if (trackingTable.RecId && MGCLatticeWorkflowLifecycleBusinessEvent::isReportableAction(trackingTable.TrackingType))
{
MGCLatticeWorkflowLifecycleBusinessEvent::newFromTracking(trackingTable).send();
}
}
}
Payload Contract
One row per [DataMember], in declaration order. Sources are the action's WorkflowTrackingTable row, its WorkflowTrackingWorkItem and WorkflowTrackingCommentTable rows, and the workflow instance's WorkflowTrackingStatusTable row (joined on WorkflowTrackingTable.WorkflowTrackingStatusTable), mapped in initialize().
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
action | Action | str | Derived from WorkflowTrackingTable.TrackingType by actionName() | See the table above |
trackingType | Tracking Type | int | WorkflowTrackingTable.TrackingType (as integer) | For example 4 Approval, 9 Creation, 15 Fault, 19 Rejection, 23 Submission |
trackingTypeName | Tracking Type Name | str | WorkflowTrackingTable.TrackingType (enum symbol) | For example "Approval" |
workflowCorrelationId | Workflow Correlation ID | str | WorkflowTrackingStatusTable.CorrelationId | The workflow instance's GUID, formatted with braces; identical on every action of one workflow instance |
workflowConfiguration | Workflow Configuration | str | WorkflowTrackingStatusTable.ConfigurationName | Name of the workflow configuration |
workflowType | Workflow Type | int | WorkflowTrackingStatusTable.WorkflowType (as integer) | WorkflowTrackingStatusWorkflowType: 0 = Workflow, 1 = DependentSubworkflow, 2 = IndependentSubworkflow |
workflowTypeName | Workflow Type Name | str | WorkflowTrackingStatusTable.WorkflowType (enum symbol) | "Workflow", "DependentSubworkflow", or "IndependentSubworkflow" |
legalEntity | Legal Entity | str | WorkflowTrackingStatusTable.ContextCompanyId | Company of the workflow document, in lower case |
documentTableName | Document Table Name | str | tableId2Name(WorkflowTrackingStatusTable.ContextTableId) | Empty when no context table is recorded |
documentRecId | Document Record ID | int64 | WorkflowTrackingStatusTable.ContextRecId | |
step | Step | str | WorkflowTrackingTable.Name | Name recorded for the tracking row - the workflow element or step the action occurred on |
actionByUser | Action By User | str | WorkflowTrackingTable.User | User the workflow framework recorded for the action |
assignedToUser | Assigned To User | str | WorkflowTrackingWorkItem.ToUser; for Assigned, the user of the new work item (WorkflowWorkItemTable.UserId) when ToUser is empty | Set for Assigned and Delegated; empty for most other actions |
comment | Comment | str | WorkflowTrackingCommentTable.Comment | The comment the user entered with the action; empty when none was entered |
actionDateTime | Action Date Time | utcdatetime | DateTimeUtil::utcNow() when the contract is built | Moments after the action is recorded; \/Date(ms)\/ form |
Every Lattice event also carries the Lattice ordering and correlation envelope, inherited from MGCLatticeBusinessEventContractBase: eventSequence (Int64 - increasing across the whole catalog and all companies, allocated when the event is raised; it orders the events of one record, gaps are normal and permanent, see the README), correlationId (String - always Scope:Key; groups emissions that belong to one logical run and defaults to Event: plus a GUID unique to this emission) and schemaVersion (Int - the payload shape version; 1 for this contract). D365 F&O also adds its standard envelope fields to every business event payload: BusinessEventId, BusinessEventLegalEntity, ContextRecordSubject, ControlNumber, EventId, EventTime, EventTimeIso8601, InitiatingUserAADObjectId, MajorVersion, MinorVersion, and ParentContextRecordSubjects. Do not rely on the order of members in the delivered JSON.
This event doesn't call correlateTo, so the Lattice correlationId is unique to each emission; to follow one workflow instance, group on workflowCorrelationId.
Example Payload
A purchase requisition approved in USMF:
{
"BusinessEventId": "MGCLatticeWorkflowLifecycleBusinessEvent",
"ControlNumber": 5637151198,
"EventId": "8A4F1C62-D3B0-4E75-91A8-6C2E0F9B7D13",
"EventTime": "\/Date(1790260337000)\/",
"EventTimeIso8601": "2026-09-24T14:32:17.9217191Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{35AE4787-1725-1466-483B-094783187616}",
"ParentContextRecordSubjects": [],
"eventSequence": 48690,
"correlationId": "Event:2c7e0b93-a51f-4d68-b3e4-9f16d8a05c27",
"schemaVersion": 1,
"action": "Approved",
"trackingType": 4,
"trackingTypeName": "Approval",
"workflowCorrelationId": "{6B3D9E1A-0F42-4C87-A5D3-7E28B1C94F60}",
"workflowConfiguration": "Purchase requisition review",
"workflowType": 0,
"workflowTypeName": "Workflow",
"legalEntity": "usmf",
"documentTableName": "PurchReqTable",
"documentRecId": 5637145110,
"step": "Approve purchase requisition",
"actionByUser": "Admin",
"assignedToUser": "",
"comment": "Approved within budget.",
"actionDateTime": "\/Date(1790260337000)\/"
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Workflow lifecycle action") or by filtering the Category column to System administration. Select it and use Activate to bind it to a configured endpoint (for example, an Azure Service Bus queue, Event Grid topic, or HTTPS webhook). No Lattice setup is needed; the event covers every configured workflow. Because it fires for all workflow types and companies, filter on documentTableName, workflowConfiguration, or company in the subscriber.