Lattice - Product Offerings
Magicite · Suite integration platform for Microsoft Dynamics 365 Finance & Operations
Real-time process events for D365 F&O, delivered by the business-events capability of the Lattice platform.
1. Overview & Value Proposition
Microsoft Dynamics 365 Finance & Operations ships with a business events framework, and its standard catalog looks long (the reference list Lattice ships for its coverage report, taken from a Finance and Operations environment, has 211 entries), but most of its entries are workflow events, generated for each configured workflow, and Human resources, batch, alert and background operation events. The finance and supply chain events are comparatively few, and most sit at the document-posting layer (invoice posted, payment posted, purchase order confirmed). The moments your integrations actually care about - a production order started, a transfer order shipped, a customer placed on credit hold, a quality inspection passed - have no native event. Integration teams are left polling tables on a timer, building brittle custom batch jobs, or bolting change-tracking onto entities that were never designed for it.
Lattice closes that gap. It adds 81 process-level business events spanning sixteen modules, each capturing a specific operational moment as it happens and pushing an enriched, integration-ready payload to the endpoint of your choice.
Key benefits:
- Real-time, not polling. Events fire the instant the underlying transaction commits, eliminating polling latency, missed changes, and the database load of scheduled scans.
- Zero-code activation. Every event surfaces in the standard Business Events Catalog (System Administration → Business Events). Activate the events you want, point them at an endpoint, and you are live - no developer involvement required.
- Endpoint-agnostic. Because these are standard D365FO business events, they route to any supported endpoint: Azure Service Bus, Azure Event Grid, HTTPS/webhook, Power Automate, and more.
- Enriched, business-readable payloads. Status fields carry both the numeric enum value and a human-readable status name (e.g.
productionStatusName,loadStatusName). Financial events carry enriched amounts and currency codes so downstream systems don't have to re-derive them. - Built the standard way. Each event follows Microsoft's
BusinessEventsBase/BusinessEventsContractpattern with Chain of Command triggers, so it behaves exactly like a first-party event in monitoring, retry, and governance. - Never blocks the business. Delivery is post-commit: the event is recorded with the business transaction and sent after it commits. A delivery failure never rolls back or blocks the underlying business action.
The result: a curated, supportable library that turns D365 F&O into a first-class event source for your integration fabric - without custom one-off development for each signal you need.
Business events are one of three Lattice capabilities. Integration operations provides 182 inbound REST operations across 30 services; Data entities provides 149 data entities, 133 of them public for OData and 15 of them set-based import entities for high-volume DMF loads. All three ship in a single model and a single deployable package.
Business events are never license-gated; only Lattice service write operations and the interactive actions that run Lattice processing are.
2. Offering Catalog
All 81 events, grouped by module. The "business moment" text is the event's own catalog description as it appears in D365 F&O; payload fields are the contract's data members.
Customer
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Collection case changed | Fires when a customer collection case is opened or closed in Credit and collections, carrying the customer, case, status, action, and balance. | legalEntity, customerAccount, customerName, caseId, caseStatus, caseStatusName, +3 more |
| Collection letter posted | Fires when a collection letter is posted for a customer, carrying the customer, letter number and dunning level, letter and due dates, fee and currency, posting date and fee voucher. | legalEntity, customerAccount, customerName, collectionLetterNum, collectionLetterCode, collectionLetterCodeName, +8 more |
| Customer created | Fires when a new customer master record is created in a legal entity. | legalEntity, customerAccount, customerName, customerGroup, crossReferences |
| Customer credit limit exceeded | Fires when a credit limit check finds a customer's balance plus the amount being checked over the credit limit in effect, such as the credit management limit (for example while entering or posting a sales order or a free text invoice), with all amounts in accounting currency. | legalEntity, customerAccount, customerName, creditLimitMST, accountingCurrencyCode, balanceMST, +3 more |
| Customer hold status changed | Fires when a customer's hold status (Blocked) changes during a customer update. Carries the new and the previous status. | legalEntity, customerAccount, customerName, blockedStatus, blockedStatusName, previousBlockedStatus, +3 more |
| Customer updated | Fires whenever an existing customer master record is modified and saved. | legalEntity, customerAccount, customerName, customerGroup, crossReferences |
| Dunning level changed | Fires when a collection letter moves an open customer transaction to a different collection letter (dunning) level, normally when the letter is posted, carrying the transaction and its previous and new level. | legalEntity, customerAccount, collectionLetterNum, collectionLetterCode, collectionLetterCodeName, previousCollectionLetterCode, +7 more |
| E-invoice submission status changed | Fires when the Electronic invoicing integration logs a document submission, with its first status, and each time the submission's status changes afterwards (for example completed or failed), carrying the legal entity, source document, status and UTC submission time. | legalEntity, documentReference, sourceTableName, sourceRecId, submissionStatus, submissionStatusName, +2 more |
| Free text invoice posted | Fires when a free text invoice that is not tied to a sales order is posted in Accounts receivable. | legalEntity, invoiceId, invoiceAccount, invoiceDate, invoiceAmount, invoiceAmountMST, +2 more |
| Return credit note posted | Fires when the credit note of a sales return order is posted (the return order is invoiced), carrying the credit note number, return order, RMA number, customer, amount and currency. | legalEntity, invoiceId, salesOrderId, rmaNumber, invoiceAccount, amount, +2 more |
| Return order received | Fires when returned goods are received and registered at the warehouse for a sales return order line, carrying the RMA number, item, quantity, disposition code and warehouse. | legalEntity, rmaNumber, salesOrderId, itemId, quantity, dispositionCode, +2 more |
| Sales order invoice posted | Fires when a sales order invoice or credit note is posted in Accounts receivable, after the invoice totals are written, carrying the invoice account, sales order, invoice number and date, amount and currency. Pro forma invoices do not raise it. | legalEntity, invoiceAccount, salesOrderId, invoiceId, invoiceDate, invoiceAmount, +2 more |
| Sales order line changed | Fires when a sales order line is modified, carrying before and after values for quantity, price, and the requested receipt and shipping dates. | legalEntity, salesOrderId, itemId, inventTransId, lineNumber, previousQuantity, +9 more |
| Sales price trade agreement changed | Fires when a sales price trade agreement record (a price agreement with relation Price (sales)) is created or updated for any party type - a specific customer, a price group, or all customers - carrying the party type and the account and item relation. Rows written by trade agreement journal posting raise it only when the skip price agreement alert parameters are No. | legalEntity, isUpdate, priceType, priceTypeName, accountCode, accountCodeName, +14 more |
Vendor
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Vendor ASN line changed | Fires when a purchase advanced shipping notice (ASN) line is created or the quantity it announces changes, carrying the purchase order, shipment and load references, item, quantity and previous quantity, unit and batch expiration so receiving warehouses and TMS learn about inbound freight. | legalEntity, purchaseOrderId, shipmentId, loadId, itemId, inventTransId, +7 more |
| Vendor check issued | Fires when a check payment is issued to a vendor: the check moves into Payment status from a status in which it had not been issued yet. A check returning to Payment from Cancel pending does not raise it. | legalEntity, bankAccountId, checkNumber, amount, currencyCode, recipientName, +3 more |
| Vendor created | Fires when a new vendor master record is created in Finance and Operations. | legalEntity, vendorAccount, vendorName, vendorGroup, currencyCode, crossReferences |
| Vendor hold status changed | Fires when a vendor's hold (blocked) status is applied, changed, or released, or when a vendor is created already on hold, carrying the new and the previous status. | legalEntity, vendorAccount, vendorName, blockedStatus, blockedStatusName, previousBlockedStatus, +3 more |
| Vendor payment posted | Fires once per vendor posting when a vendor payment journal is posted, for a vendor on the line's account or offset account, carrying the journal ID, voucher, vendor, amount signed from the vendor's side with its debit or credit side, and payment reference. | legalEntity, journalId, voucher, vendorAccount, vendorLegalEntity, isOffsetAccount, +7 more |
| Vendor updated | Fires when an existing vendor master record is modified and saved. | legalEntity, vendorAccount, vendorName, vendorGroup, currencyCode, crossReferences |
Sales
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Retail info-code response captured | Fires when an info code (reason code) response record is created in headquarters by application code or a data import, with the info code and subcode, response text and amount, transaction and line numbers, store, terminal and staff. Responses uploaded from stores might not raise it. | legalEntity, infoCodeId, subInfoCodeId, information, infoAmount, infoCodeTransactionType, +8 more |
| Sales agreement confirmed | Fires when a sales agreement is confirmed and an agreement header history record for the committed agreement is written. | legalEntity, salesAgreementId, confirmationId, customerAccount, effectiveDate, expirationDate, +1 more |
| Sales order canceled | Fires when a sales order's remaining quantities are canceled and the order's status becomes Canceled. From the Cancel action it fires only once the cancellation is final, after any card pre-authorization has been voided. Return orders raise it too; the order type in the payload tells them apart. | legalEntity, salesOrderId, customerAccount, salesStatus, salesStatusName, salesType, +3 more |
| Sales order confirmed | Fires when a sales order confirmation is posted and its confirmation journal is created, carrying the order, customer, confirmation number and the confirmation total. Pro forma confirmations do not raise it. | legalEntity, salesOrderId, customerAccount, confirmationId, currencyCode, totalAmount, +1 more |
| Sales packing slip posted | Fires when a sales order packing slip is posted, recording the physical shipment of goods against a sales order. Pro forma packing slips, packing slip cancellations and return order receipts do not raise it. | legalEntity, salesOrderId, customerAccount, packingSlipId, deliveryDate, crossReferences |
| Sales price agreement created | Fires when a posted trade-agreement journal adds a sales price for an agreement (the same account, item, currency, unit, quantity break and inventory dimensions) that had no sales price in effect on the new price's From date. | legalEntity, changeType, changeTypeName, priceType, priceTypeName, accountCode, +19 more |
| Sales price agreement deleted | Fires when a sales-price trade agreement is deleted, whether by a user, by code or by posting a trade-agreement journal line that is marked for deletion. | legalEntity, changeType, changeTypeName, priceType, priceTypeName, accountCode, +19 more |
| Sales price agreement effective | Fires when a sales-price trade agreement reaches its From date, reported by the scheduled effectivity batch. A price saved with a From date the batch has already passed is not reported. | legalEntity, changeType, changeTypeName, priceType, priceTypeName, accountCode, +19 more |
| Sales price agreement expired | Fires when a sales-price trade agreement passes its To date and no other price of the same agreement (including quantity break and inventory dimensions) is in effect on the next day, reported by the scheduled effectivity batch. | legalEntity, changeType, changeTypeName, priceType, priceTypeName, accountCode, +19 more |
| Sales price agreement modified | Fires when a posted trade-agreement journal changes an existing sales price. Carries the previous amount and the names of the fields that changed; a journal line that changes nothing does not raise it. | legalEntity, changeType, changeTypeName, priceType, priceTypeName, accountCode, +19 more |
| Sales price agreement superseded | Fires when a posted trade-agreement journal adds a sales price for an agreement that already had a sales price in effect on the new price's From date. Carries that earlier price's amount and record ID; the earlier price itself is not changed. | legalEntity, changeType, changeTypeName, priceType, priceTypeName, accountCode, +19 more |
| Sales quotation confirmed | Fires when a sales quotation is confirmed and a quotation confirmation journal record is created. | legalEntity, quotationId, confirmationId, salesOrderId, customerAccount, confirmationDate, +1 more |
| Sales return order created | Fires when a sales return order used to bring customer-returned goods back into inventory is created. | legalEntity, salesOrderId, customerAccount, returnReasonCodeId, crossReferences |
Purchasing
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Purchase agreement confirmed | Fires when a purchase agreement is confirmed and an agreement header history record capturing the negotiated terms is written. | legalEntity, purchAgreementId, vendorAccount, effectiveDate, expirationDate, crossReferences |
| Purchase requisition approved | Fires the moment a purchase requisition completes its approval workflow and its status transitions to Approved. | legalEntity, buyingLegalEntities, purchReqId, requisitionName, requesterPersonnelNumber, crossReferences |
| Purchase return order created | Fires when a purchase return order representing goods being sent back to a vendor is created. | legalEntity, purchaseOrderId, vendorAccount, returnReasonCodeId, crossReferences |
Inventory
| Event | Business moment captured | Key payload fields |
|---|---|---|
| External item changed | Fires when a customer or vendor external item cross-reference is created or updated. | legalEntity, isUpdate, itemId, externalItemId, externalItemText, description, +6 more |
| Inventory closing completed | Fires when an inventory close or an inventory recalculation has finished for a legal entity, after settlement, cost adjustment and ledger posting, and says which of the two ran. | legalEntity, closingDate, adjustmentType, voucher, adjustmentTypeName |
| Inventory on-hand changed | Fires once per item, site and warehouse whose net physical on-hand changed in a committed inventory transaction, with the change and that site and warehouse's current on-hand quantities. | legalEntity, itemId, siteId, warehouseId, physicalInventoryChange, availableOrdered, +8 more |
| Item back in stock | Fires when an item's available physical quantity in a site and warehouse goes from zero or less to above zero in a committed transaction, at most once per item, site and warehouse per transaction. | legalEntity, itemId, siteId, warehouseId, previousAvailablePhysical, currentAvailablePhysical, +2 more |
| Picking list canceled | Fires when a picking list or an individual picking line is canceled, listing only the lines the cancellation canceled. Nothing is sent when a cancellation cancels no lines. | legalEntity, pickingRouteId, orderNumber, transType, transTypeName, routeStatus, +4 more |
| Quality order failed | Fires when an inventory quality order is validated with a failing result and its status transitions to Fail. | legalEntity, qualityOrderId, itemId, itemSearchName, orderStatus, orderStatusName, +13 more |
| Quality order passed | Fires when a quality order passes validation and its order status transitions to Pass. | legalEntity, qualityOrderId, itemId, testGroupId, referenceId, orderStatus, +1 more |
| Released product created | Fires when the product release process creates a released product in a legal entity, with the item number, product, search name, item type and lifecycle state. | legalEntity, itemId, productRecId, searchName, itemType, itemTypeName, +2 more |
| Transfer order picking list created | Fires when Generate picking list creates a picking list for a transfer order, listing the lines to pick. The picking list is either activated for picking or already completed, as set by the transfer order picking route status parameter. | legalEntity, pickingRouteId, orderNumber, transType, transTypeName, routeStatus, +4 more |
| Transfer order received | Fires when an inventory transfer order completes receiving at the destination warehouse and its status transitions to Received. | legalEntity, transferOrderId, fromWarehouseId, toWarehouseId, transferStatus, transferStatusName, +1 more |
| Transfer order shipped | Fires when an inventory transfer order transitions into the Shipped status and goods are in transit to the destination warehouse. | legalEntity, transferOrderId, fromWarehouseId, toWarehouseId, transferStatus, transferStatusName, +1 more |
| Warehouse load shipped | Fires when a warehouse load completes outbound shipping and its load status transitions to Shipped, from load ship confirmation or from transport load ship confirmation (including the mobile app). | legalEntity, loadId, shipmentIds, shipmentId, carrierCode, loadStatus, +1 more |
| Warehouse picking completed | Fires when sales, transfer order, production or kanban picking work closes, with the work order type, the order, shipment and load references, and one entry per completed pick line with its item, quantity, unit, location and operator. | legalEntity, workId, workTransType, workTransTypeName, orderNumber, shipmentId, +6 more |
| Warehouse work completed | Fires when warehouse work is completed: its status changes to Closed, or it is created already closed, for example a movement or adjustment that is executed at once. | legalEntity, workId, workStatus, workStatusName, workTransType, workTransTypeName, +6 more |
Production
| Event | Business moment captured | Key payload fields |
|---|---|---|
| BOM calculation completed | Fires when a bill of materials cost calculation finishes and its calculated cost result record is written for an item. | legalEntity, itemId, costPrice, calculationDate |
| BOM version approved | Fires when the BOM version approval operation approves a bill of materials version that was not approved before. | legalEntity, itemId, bomId, bomName, approverPersonnelNumber, approverName, +5 more |
| Production order ended | Fires when a production order reaches the Completed (ended) status, the final stage of the production lifecycle. | legalEntity, productionOrderId, itemId, itemSearchName, productionStatus, productionStatusName, +4 more |
| Production order estimated | Fires when a production order's cost estimation has been completed and its estimated material and routing costs are available. | legalEntity, productionOrderId, itemId, crossReferences |
| Production order reported as finished | Fires when a production order reaches the Reported as finished status and manufactured output has been reported against the order. | legalEntity, productionOrderId, itemId, itemSearchName, productionStatus, productionStatusName, +4 more |
| Production order scheduled | Fires when a production order reaches the Scheduled status, through operations or job scheduling or when firming a planned order creates it as Scheduled. | legalEntity, productionOrderId, itemId, itemSearchName, productionStatus, productionStatusName, +1 more |
| Production order started | Fires when a production order transitions into the Started status and production has begun on the shop floor. | legalEntity, productionOrderId, itemId, itemSearchName, productionStatus, productionStatusName, +1 more |
| Production pick list posted | Fires when a production pick list journal is posted, signaling that materials have been consumed against a production order. | legalEntity, productionOrderId, journalId, itemId, itemSearchName, productionStatus, +3 more |
| Production route card posted | Fires when a production route card journal is posted, confirming reported operation time and quantities for a production order. | legalEntity, productionOrderId, journalId, itemId, itemSearchName, productionStatus, +4 more |
Finance
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Advanced bank reconciliation completed | Fires when an Advanced bank reconciliation worksheet is marked as reconciled, carrying the reconciliation ID, bank account, the bank statements it covers, the reconciled date, and the counts and bank-currency totals of the matched statement lines and bank transactions. The classic bank account reconciliation does not raise it. | legalEntity, reconciliationId, bankAccountId, cutOffDate, statementIds, statementsFromDateTime, +8 more |
| Bank reconciliation completed | Fires when a bank statement is reconciled with the Reconcile account action of the bank account reconciliation, carrying the bank account, statement number and date, ending balance, and the count and accounting-currency total of the reconciled bank transactions. Advanced bank reconciliation raises the Advanced bank reconciliation completed event instead. | legalEntity, bankAccountId, statementNumber, statementDate, currencyCode, endingBalance, +3 more |
| General journal posted | Fires when a general (daily) journal transitions from unposted to posted in the General ledger. | legalEntity, journalId, journalName, description, postedDate, crossReferences |
Fixed assets
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Fixed asset acquisition posted | Fires for each fixed asset acquisition transaction written to a book, including the reversal or reclassification of an acquisition, which the payload flags. | legalEntity, assetId, bookId, acquisitionAmountMST, transDate, voucher, +3 more |
| Fixed asset disposal posted | Fires for each fixed asset disposal transaction, by sale or by scrap, written to a book, including the reversal or reclassification of a disposal, which the payload flags. | legalEntity, assetId, bookId, disposalAmountMST, transDate, voucher, +3 more |
| Maintenance work order completed | Fires when a maintenance work order transitions into a lifecycle state that stamps its actual end (work is completed). | legalEntity, workOrderId, workOrderType, description, lifecycleState, functionalLocation, +11 more |
| Maintenance work order created | Fires once for each new Asset Management maintenance work order, as the transaction that creates it commits, describing the work order with its lines, assets and first lifecycle state. | legalEntity, workOrderId, workOrderType, description, lifecycleState, functionalLocation, +11 more |
| Maintenance work order scheduled | Fires when a maintenance work order moves to the scheduled lifecycle state of its lifecycle model, which is what work order scheduling does. | legalEntity, workOrderId, workOrderType, description, lifecycleState, functionalLocation, +11 more |
| Maintenance work order started | Fires when a maintenance work order transitions into a lifecycle state that stamps its actual start (work has begun). | legalEntity, workOrderId, workOrderType, description, lifecycleState, functionalLocation, +11 more |
Project
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Project invoice posted | Fires when a project invoice is posted and its project invoice journal is created, carrying the project, invoice number and date, customer and the invoice total in the invoice currency. Pro forma invoices do not raise it. | legalEntity, projectId, invoiceId, invoiceDate, invoiceAccount, invoiceAmount, +1 more |
| Project task assigned | Fires when a resource is assigned to a project activity (task), or when an assignment's resource or load percentage changes. | legalEntity, projectId, assignedHours, activityNumber, resourceId, workerPersonnelNumber, +3 more |
Planning
| Event | Business moment captured | Key payload fields |
|---|---|---|
| MRP run completed | Fires once when a master planning run of the built-in planning engine finishes calculating a plan; helper threads, forecast scheduling, firming and order explosions do not raise it, and neither does a canceled run. Master planning runs made with Planning Optimization do not raise it. | legalEntity, planId |
Product information
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Retail assortment published | Fires when Process assortments publishes a retail assortment for the first time in a legal entity, or when its effective item list there has changed, listing the items with a price at publish (customer-specific when the assortment is tied to a customer). | legalEntity, customerLegalEntity, customerAccount, currencyCode, assortmentId, assortmentName, +4 more |
Platform and integration
| Event | Business moment captured | Key payload fields |
|---|---|---|
| Aggregate measurement refresh completed | Fires when a full entity store aggregate measurement refresh finishes, carrying the measurement name, refresh type, execution status, start and completion times, and the duration so BI pipelines know when entity-store data is current instead of polling. | measurementName, refreshStatus, refreshStatusName, isSuccessful, startedDateTime, completedDateTime, +1 more |
| Batch job status changed | Fires when a batch job's status is changed through the batch job record, for example when an operator withholds, releases or cancels it, carrying the previous and new status, caption, company, start and end times, and task count. Jobs that match an enabled batch job event filter are filtered out. | batchJobRecId, caption, legalEntity, status, statusName, previousStatus, +4 more |
| Business event publish failed | Fires when publishing a business event that opts in to Lattice business event logging fails outside a database transaction and an error row is written to the Lattice business event log. Only the retail assortment published event opts in. Failures delivering to the endpoint afterwards are not covered. | failedBusinessEventId, identifier, legalEntity, failureDetails, logRecId, failedDateTime |
| Custom ad-hoc business event | Fires only when your own X++ code calls the Lattice ad-hoc business event API for a record, carrying a caller-chosen event name, a record reference (table, RecId, key fields) and a free-form JSON payload. The API is X++ only; it is not an OData action. | eventName, tableName, recId, payloadJson |
| DMF execution completed | Fires when an entity of a Data management data project execution finishes its target step in a batch import, a copy to target, a file export or a bring-your-own-database export, carrying the execution ID, data project, entity, company, derived outcome (succeeded, partially failed, failed or canceled) and the record and error counts. Imports run without batch are reported only in limited cases. | legalEntity, executionId, definitionGroup, entity, source, outcome, +11 more |
| Integration item parked | Raised when a failed Lattice integration item is parked for manual review: straight away for a non-retryable failure, or when the scheduled dead-letter retry sweep has used up its retries. Carries only non-sensitive identification and diagnostic fields; no payload, request ID or secret is included. | deadLetterId, sourceType, sourceTypeName, serviceName, operationName, errorCode, +6 more |
| Recurring data job health changed | Fires when the health state of a recurring data job that has alerts switched on changes, for example from Healthy to Failing or from Broken back to Healthy, once per change. Carries the job, its direction and data project, the previous and new health state, the reasons, and the backlog, failure, client and last message values the state was derived from. | jobName, activityId, direction, dataProject, healthState, previousHealthState, +23 more |
| Workflow lifecycle action | Fires when a workflow action is recorded - a work item assigned, submitted, approved, rejected, delegated, escalated, completed, or failed - carrying the action, workflow, document context, step, and the acting user. | action, trackingType, trackingTypeName, workflowCorrelationId, workflowConfiguration, workflowType, +9 more |
| Workflow stalled or failed | Fires from a scheduled scan for each workflow instance that has faulted and each work item left unactioned beyond a configurable age threshold, once per condition and again only if the condition changes. Carries the workflow ID and name, company, document, current step, age and a detail message so an administrator can be alerted. | alertReason, workflowCorrelationId, workflowId, workflowConfiguration, workflowType, workflowTypeName, +13 more |
3. Integration Scenarios
The events are designed to be composed into end-to-end integration flows. Six representative scenarios:
3.1 Real-time CRM customer sync
Events: Customer created, Customer updated, Customer hold status changed Endpoint: Azure Service Bus → CRM connector (or Power Automate → Dataverse) A new or changed customer in D365 F&O is pushed to the Service Bus topic the moment it commits. The CRM connector upserts the account; the hold-status event additionally flags the account and alerts the sales owner - so reps never quote a customer who can no longer transact.
3.2 ASN / carrier integration on shipment
Events: Warehouse load shipped, Sales packing slip posted, Transfer order shipped
Endpoint: Azure Event Grid → TMS / 3PL webhook
When a load ships, the event carries shipmentId and carrierCode. An Event Grid subscription triggers an Azure Function that builds an ASN (EDI 856) and notifies the carrier and customer. Transfer order shipped feeds the same flow for inter-site moves, so the receiving 3PL sees in-transit stock immediately.
3.3 Quality-hold notification and stock release
Events: Quality order passed, Quality order failed Endpoint: Power Automate → Teams / QMS HTTPS endpoint A passed quality order releases held stock and records the result in the QMS. The Quality order failed event handles the opposite outcome - a failed inspection routes a CAPA/non-conformance workflow and blocks the affected quantity from shipping - closing the inspection-outcome loop in real time.
3.4 Finance close automation
Events: General journal posted, Free text invoice posted, Inventory closing completed, Fixed asset disposal posted Endpoint: Azure Service Bus → consolidation/reporting platform Each posting streams to a reporting GL and the e-invoicing network as it happens. Inventory closing completed acts as a gate signal that triggers the next set of period-close tasks in an orchestration tool - turning a manual checklist into an event-driven pipeline.
3.5 Manufacturing execution (MES) handshake
Events: Production order scheduled, Production order started, Production order reported as finished, Production order ended
Endpoint: HTTPS webhook → MES
The production lifecycle is mirrored into the MES without polling. Started triggers material staging; Reported as finished (with reportedFinishedGoodQuantity / reportedFinishedErrorQuantity) updates yield and available-to-promise; Ended closes the work order and releases final cost actuals.
3.6 Credit and collections escalation
Events: Customer credit limit exceeded, Dunning level changed, Collection letter posted, Collection case changed Endpoint: Power Automate → collections workspace / Teams Credit exposure and dunning progression stream out as they happen. An exceeded credit limit alerts the credit controller with the full exposure breakdown before an order is released; dunning and collection-letter events drive the follow-up cadence in a collections tool without nightly extracts.
4. Technical Foundation
Every event is built on Microsoft's standard business events framework:
- Standard pattern. Each event pairs a
BusinessEventsBaseevent class with aBusinessEventsContractpayload contract, exactly as Microsoft's first-party events do. This guarantees consistent behavior in the catalog, in monitoring, and in retry/governance tooling. - Process-method triggers. Events fire from Chain of Command extensions on the process method that causes the data change, rather than on raw table
insert()/update()hooks wherever a process method exists. This makes them cancellation-safe and partial-posting-safe. - Enable per event. Each event is independently activated in the Business Events Catalog and checked at runtime via
BusinessEventsConfigurationReader, so inactive events carry no overhead. - At-least-once delivery. Consumers must be idempotent by event id.
- Single model. Business events ship inside the single Lattice model alongside the service and data-entity surfaces, for clean deployment and version management.
5. Requirements
- D365 F&O - version-agnostic. Lattice targets the standard, stable business events framework and Chain of Command extension model, both long-standing platform features. It is not tied to a specific application release and is designed to carry forward across D365 F&O updates.
- Model dependencies. The Lattice model references the standard application stack -
ApplicationSuite,ApplicationFoundation,ApplicationCommon,ApplicationPlatform,ApplicationWorkspaces,Ledger,Subledger,Tax,Directory,Currency, and related foundation modules - all present in any standard F&O environment. No third-party ISV dependencies are required. - Activation prerequisite. A configured business events endpoint (Azure Service Bus, Event Grid, HTTPS, or Power Automate) to receive the events; standard D365 F&O security to access the Business Events Catalog.
Lattice is a Magicite product. Element names in the shipped model carry the MGCLattice prefix; OData collection names carry the Lattice prefix.