Sales order confirmed
Fires when a sales order confirmation is posted in D365FO. Posting a confirmation creates a CustConfirmJour record (the confirmation journal header), which represents the moment the customer-facing order confirmation document is generated. Pro forma confirmations do not raise it. Downstream systems can use this event to notify the customer, trigger fulfillment workflows, or sync the confirmed order into external CRM/commerce platforms.
| Event class | MGCLatticeSalesOrderConfirmedBusinessEvent |
| Contract class | MGCLatticeSalesOrderConfirmedBusinessEventContract |
| Category | Sales orders |
| Module | ModuleAxapta::SalesOrder |
| Label IDs | SalesOrderConfirmedBusinessEventName / SalesOrderConfirmedBusinessEventDescription |
| Trigger | SalesConfirmJournalPost.postJournalPost() -> after a confirmation journal is posted, unless the posting is pro forma |
Trigger / Hook
- Extension class:
MGCLatticeSalesConfirmJournalPost_Class_Extension, decorated with[ExtensionOf(classStr(SalesConfirmJournalPost))]. - CoC method signature:
public void postJournalPost()(no parameters) - the form-letter post-completion process method, the true business moment, rather than theCustConfirmJour.insert()table write. - Firing condition: after
next postJournalPost()completes, the journal is resolved viathis.parmJournalTable() as CustConfirmJourand the event sends only whencustConfirmJour.RecIdis non-zero and the posting is not pro forma. The form-letter framework (FormletterService.createAndPostJournal()) callspostJournalPost()once for every confirmation journal it created, so the event fires once per confirmation journal; the single-order, summary-update and batch posting paths all go through it. - Pro forma confirmations: a pro forma confirmation also creates a temporary
CustConfirmJour(deleted after the pro forma document is printed) andpostJournalPost()runs for it. The hook checks the posting'sisProforma()flag and sends nothing for it. - Transaction:
postJournalPost()runs inside the posting transaction ofFormletterService.processJournal().BusinessEventsBase.send()only writes the event to the business events commit log inside that transaction and delivery happens after commit, so a posting that fails or is rolled back - including a simulated posting, which ends withttsabort- never delivers. - Enablement gate: guarded by
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeSalesOrderConfirmedBusinessEvent)), so the event only sends when activated in the business events catalog.
/// <summary>
/// Triggers the sales order confirmed business event after a confirmation journal is posted; pro forma
/// confirmations are not reported.
/// </summary>
public void postJournalPost()
{
CustConfirmJour custConfirmJour;
next postJournalPost();
custConfirmJour = this.parmJournalTable() as CustConfirmJour;
if (custConfirmJour.RecId
&& !this.isProforma()
&& BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeSalesOrderConfirmedBusinessEvent)))
{
MGCLatticeSalesOrderConfirmedBusinessEvent::newFromCustConfirmJour(custConfirmJour).send();
}
}
Payload Contract
One row per [DataMember], in declaration order. All sources are fields on the triggering CustConfirmJour record, mapped in initialize().
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
legalEntity | Legal Entity | DataAreaId | CustConfirmJour.DataAreaId | Company/legal entity of the confirmation journal |
salesOrderId | Sales Order ID | SalesId | CustConfirmJour.SalesId | The confirmed sales order number |
customerAccount | Customer Account | CustAccount | CustConfirmJour.OrderAccount | Order account (the customer the confirmation is for) |
confirmationId | Confirmation ID | ConfirmId | CustConfirmJour.ConfirmId | Confirmation document number |
currencyCode | Currency Code | CurrencyCode | CustConfirmJour.CurrencyCode | Transaction currency of the order |
totalAmount | Total Amount | AmountCur | CustConfirmJour.ConfirmAmount | Total of the confirmation document in the transaction currency: the lines after line and total discounts, plus charges, sales tax and round-off |
crossReferences | Cross references | List of MGCLatticeCrossReferenceEventContract | MGCLatticeCrossReferenceEventHelper::listForSalesOrder(CustConfirmJour.SalesId, CustConfirmJour.DataAreaId) | Keys external systems hold for the sales order that was confirmed: one { externalSystem, externalKey } object per external system, ordered by external system, historical keys included; [] when it has none. See Cross-reference keys. The keys are the sales order's, not the journal's. |
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 sent inside the business transaction; it orders the events of one record, but two transactions can commit in the opposite order of their values, and gaps are normal and permanent - see the events overview), correlationId (String - always Scope:Key: Event: followed by a GUID unique to this emission, unless the event joins a run) 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.
Example Payload
{
"BusinessEventId": "MGCLatticeSalesOrderConfirmedBusinessEvent",
"ControlNumber": 5637148921,
"EventId": "2464289A-9A4A-4C8F-864D-3BA5D9F15A5F",
"EventTime": "\/Date(1790260337000)\/",
"EventTimeIso8601": "2026-09-24T14:32:17.0908031Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{723ABFFB-A855-D220-3FD5-DC188DDDC425}",
"ParentContextRecordSubjects": [],
"eventSequence": 48213,
"correlationId": "Event:2404b6b3-cc85-4216-a436-0e164bc3de94",
"schemaVersion": 1,
"legalEntity": "usmf",
"salesOrderId": "001787",
"customerAccount": "US-004",
"confirmationId": "CCF-00000120",
"currencyCode": "USD",
"totalAmount": 14250.75,
"crossReferences": [
{
"externalSystem": "SHOP",
"externalKey": "WEB-1004871"
}
]
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Sales order confirmed") or by filtering the Category column to Sales orders. 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).