Advanced bank reconciliation completed
Fires when an Advanced bank reconciliation worksheet is marked as reconciled - the moment D365 sets the reconciliation's Reconciled flag. It carries the reconciliation ID, bank account, cut-off and reconciled dates, the bank statements whose lines the reconciliation matched, the bank currency, the number of matched statement lines and bank transactions with their totals in bank currency, and the user who reconciled, giving treasury and cash-management systems a push signal that a reconciliation has been closed. The classic bank account reconciliation raises Bank reconciliation completed instead.
| Event class | MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent |
| Contract class | MGCLatticeAdvancedBankReconciliationCompletedBusinessEventContract |
| Category | Bank management |
| Module | ModuleAxapta::Bank |
| Label IDs | AdvancedBankReconciliationCompletedBusinessEventName / AdvancedBankReconciliationCompletedBusinessEventDescription |
| Trigger | BankReconciliationHeader::reconcile() / reconcileInBatch() -> IsReconciled goes from No to Yes |
Trigger / Hook
- Extension class:
MGCLatticeBankReconciliationHeader_Table_Extension,[ExtensionOf(tableStr(BankReconciliationHeader))]- a process hook on the two public reconcile entry points, not on the table'supdate(). - CoC method signatures:
public static void reconcile(RecId _reconciliationRecId)andpublic static void reconcileInBatch(RecId _reconciliationRecId, UserConnection _connection). - Firing condition: when the event is activated, each wrapper reads the worksheet's
IsReconciledbeforenext; afterwardsMGCLatticeAdvancedBankReconciliationCompletedBusinessEvent::raiseIfReconciliationCompleted()reads the worksheet again and sends the event when the flag changed from No to Yes (isReconciliationCompleted). A run that fails validation, does not get the bank account lock, or rolls back leaves the flag at No and raises nothing; reconciling a worksheet that is already reconciled does not raise it again. - Process: the reconciliation worksheet's Mark as reconciled action, run interactively (
reconcile) or in batch (reconcileInBatch). Both run the privateBankReconciliationHeader::reconcileInner, which inside its own transaction writes the reconciliation history, marks every matched statement line and bank document reconciled, and then setsIsReconciledto Yes andReconciledDateto today (in the user's time zone). No other standard code setsIsReconciledto Yes. - Other writers: worksheets written by data entities, imports or code outside these two methods do not raise the event.
- Matched data: when the event is built, the worksheet's matching items (
BankReconciliationMatchingItemViewfor the reconciliation) are read - the same rows the Reconcile step has just walked. - Unreconcile sets
IsReconciledback to No and raises nothing. A worksheet that is unreconciled and then marked as reconciled again raises the event again, with the matches it has then. - The classic bank account reconciliation is not covered. It reconciles one
BankAccountStatementwith the Reconcile account action and raises Bank reconciliation completed; it never touchesBankReconciliationHeader. - Timing: the event is sent after
nextreturns, whenreconcileInner's transaction has committed (unless the caller holds an outer transaction, in which casesend()writes to the business events commit log inside it and delivery waits for its commit). A reconciliation that fails and rolls back never delivers. Building the payload only reads data, and a bank document that cannot be valued counts with amount 0 rather than failing. - Enablement gate:
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent)), checked before the worksheet is read at all; while the event is not activated the wrappers read nothing and build nothing.
public static void reconcile(RecId _reconciliationRecId)
{
// Read the worksheet only when the event is active (cached check); Yes makes the raise below a no-op.
NoYes previousIsReconciled = BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent))
? BankReconciliationHeader::find(_reconciliationRecId).IsReconciled
: NoYes::Yes;
next reconcile(_reconciliationRecId);
MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent::raiseIfReconciliationCompleted(_reconciliationRecId, previousIsReconciled);
}
// reconcileInBatch(RecId, UserConnection) is wrapped the same way.
Payload Contract
One row per [DataMember], in declaration order. initialize() reads the reconciled BankReconciliationHeader row and its bank account, then counts and totals the statement lines and bank documents matched on the worksheet and collects the statements those lines belong to.
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
legalEntity | Legal Entity | DataAreaId | BankReconciliationHeader.DataAreaId | Company of the bank account, in lower case (for example usmf). |
reconciliationId | Reconciliation ID | BankReconciliationId | BankReconciliationHeader.ReconciliationId | The reconciliation worksheet. |
bankAccountId | Bank Account ID | CompanyBankAccountId | BankReconciliationHeader.AccountId | Bank account. |
cutOffDate | Cut-off Date | BankReconciliationCutOffDate | BankReconciliationHeader.CutOffDate | The worksheet's cut-off date (date, \/Date(milliseconds)\/ form). |
statementIds | Statement IDs | List of BankStatementId | BankStmtISOAccountStatement.Identification of each statement with at least one matched line, ordered by FromDateTime | The bank statements the reconciliation covers, as a JSON array of strings; a worksheet can span several. [] when no statement line was matched. |
statementsFromDateTime | Statements From | BankStmtISODateTime (utcdatetime) | Earliest BankStmtISOAccountStatement.FromDateTime of those statements | Start of the period the covered statements span; the empty date-time ("\/Date(-2208988800000)\/") when statementIds is empty. |
statementsToDateTime | Statements To | BankStmtISODateTime (utcdatetime) | Latest BankStmtISOAccountStatement.ToDateTime of those statements | End of that period; empty like statementsFromDateTime. |
reconciledDate | Reconciled Date | BankReconciliationReconciledDate | BankReconciliationHeader.ReconciledDate | Date the worksheet was marked as reconciled. |
currencyCode | Currency Code | CurrencyCode | BankAccountTable.CurrencyCode of the bank account | The bank currency; every amount in the payload is in this currency. |
matchedStatementLineCount | Matched Statement Line Count | int | count(RecId) of BankStmtISOReportEntry rows matched on the worksheet | Number of bank statement lines reconciled. |
matchedStatementAmount | Matched Statement Amount | AmountCur | BankReconciliationHeader.getMatchedStatementTotal() | Net total of those lines in bank currency, as the worksheet computes it: debit lines add, credit lines subtract. |
matchedBankTransactionCount | Matched Bank Transaction Count | int | Number of distinct BankDocumentTable rows matched on the worksheet | Number of bank transactions reconciled - the rows of the worksheet's bank transactions grid (bank transactions, checks, deposit slips and so on). |
matchedBankTransactionAmount | Matched Bank Transaction Amount | AmountCur | Sum of BankDocument.getBankCurrencyAmount() over those documents | Net total of those bank transactions in bank currency, including any correction amount, as the worksheet values them. |
reconciledBy | Reconciled By | UserId | curUserId() when the event is raised | The user who marked the worksheet as reconciled; when it ran in batch, the user the batch job runs as. |
The two totals are equal for one-to-one matches. Compare them rather than assume they are equal: a statement line can be reconciled without a bank transaction of the same amount, for example a line matched to a new voucher generated from the worksheet, or a match with a correction amount.
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 inside the business transaction, not when it commits; it orders the events of one business record, gaps are permanent and normal, and it must not be used to re-sequence the whole stream), correlationId (String, always Scope:Key - groups emissions that belong to one logical run; an event that joins no run carries Event: followed by a lower-case 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 does not join a run: correlationId is unique to each emission.
Example Payload
A worksheet with an August cut-off that reconciled lines from two imported bank statements.
{
"BusinessEventId": "MGCLatticeAdvancedBankReconciliationCompletedBusinessEvent",
"ControlNumber": 5637148912,
"EventId": "3E8A61D2-94B7-4C05-A1F3-6B2D7E90C4A8",
"EventTime": "\/Date(1788358328000)\/",
"EventTimeIso8601": "2026-09-02T14:12:08.4107391Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{9E0E481C-DDF2-461E-F503-CA809B9A682C}",
"ParentContextRecordSubjects": [],
"eventSequence": 48241,
"correlationId": "Event:b51d7f20-6c3e-4a98-8e17-3f0a9c2d6b84",
"schemaVersion": 1,
"legalEntity": "usmf",
"reconciliationId": "BR-000042",
"bankAccountId": "USMF OPER",
"cutOffDate": "\/Date(1788134400000)\/",
"statementIds": ["STMT-2026-08A", "STMT-2026-08B"],
"statementsFromDateTime": "\/Date(1785542400000)\/",
"statementsToDateTime": "\/Date(1788220799000)\/",
"reconciledDate": "\/Date(1788307200000)\/",
"currencyCode": "USD",
"matchedStatementLineCount": 57,
"matchedStatementAmount": 48210.75,
"matchedBankTransactionCount": 55,
"matchedBankTransactionAmount": 48210.75,
"reconciledBy": "Admin"
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Advanced bank reconciliation completed") or by filtering the Category column to Bank management. 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). The event only covers bank accounts reconciled with Advanced bank reconciliation; to cover bank accounts that still use the classic bank account reconciliation, also activate Bank reconciliation completed.
Related Events
- Bank reconciliation completed - the same moment for the classic bank account reconciliation.
- General journal posted - ledger postings, including bank-related journals.
- Vendor payment posted - vendor payments that later appear on bank statements.
- Vendor check issued - checks that clear through the bank account.