Skip to main content

Lattice Integration Operations - API Reference

Complete API reference for all custom service operations exposed by the Lattice module-specific service groups in D365 Finance & Operations.

These services are the service surface of the consolidated Lattice model - a single D365 F&O package (publisher Magicite, ISV layer 8) that holds the integration operations, data entities, and business events. AOT elements use the MGCLattice* prefix; OData collection names remain Lattice* as the public wire contract. The Lattice service surface currently comprises 30 services across 13 auto-deploying, module-specific service groups, exposing 182 service operations in total (base operations plus their *Batch bulk variants, read-only status queries, and async submit/poll).

Table of Contents​


Authentication​

All requests require OAuth2 bearer token authentication using the client_credentials grant type.

POST https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id={clientId}
&client_secret={clientSecret}
&scope={resource}/.default

Include the token in every API request:

Authorization: Bearer {access_token}
Content-Type: application/json

Endpoint Pattern​

POST {baseUrl}/api/services/{ServiceGroup}/{ServiceName}/{operationName}

Services are organized into 13 auto-deploying, module-specific service groups:

Service GroupServices
MGCLatticeAccountsReceivableServiceGroupSalesOrderPosting, SalesOrderCapture (§1a), FreeTextInvoice, SalesReturn (§6), PriceInquiry (§27), SalesTradeAgreement (§28)
MGCLatticeAccountsPayableServiceGroupPurchaseOrderPosting, PurchaseReturn (§6), VendorInvoiceJournal, VendorInvoice (§16a), VendorPaymentProposal, PurchaseRequisition
MGCLatticeInventoryServiceGroupInventoryJournalPosting, TransferOrderPosting, InventoryCost (§4a)
MGCLatticeProductionServiceGroupProductionOrderPosting
MGCLatticeGeneralLedgerServiceGroupGeneralLedgerJournal, PaymentJournal, BudgetRegister, CurrencyRevaluation
MGCLatticeJournalPostingServiceGroupJournalPosting (§8a)
MGCLatticeFixedAssetsServiceGroupFixedAsset
MGCLatticeProjectServiceGroupProjectJournal, ProjectInvoice
MGCLatticeExpenseServiceGroupExpenseReport (§13a)
MGCLatticeWorkflowServiceGroupWorkflowAction
MGCLatticeAsyncOperationServiceGroupAsyncOperation
MGCLatticeDbAccessServiceGroupDbAccess (§29)
MGCLatticeDataManagementServiceGroupDmfConfig (§35)

All thirteen groups carry AutoDeploy=Yes, so every group is published automatically on deployment. See the service-specific sections below for the correct service group to use for each operation.

Common Request Fields​

Every request contract includes these standard fields. They are listed once here and omitted from individual operation documentation for brevity.

FieldJSON KeyTypeRequiredDescription
Correlation IDCorrelationIdstring (GUID)NoCaller-supplied identifier for distributed tracing. Echoed in the response.
Request IDRequestIdstring (GUID)YesUnique identifier for this request. Must not be empty.
Legal EntityLegalEntityIdstringYesCompany/legal entity code (e.g., USMF). The operation runs in this legal entity, whatever the caller's default company; it must exist.
User ContextUserContextstringNoInformational caller identifier (e.g., Admin). Recorded in the service call log (UserContext); never used for authorization - the operation always runs with the rights of the authenticated caller, who is recorded as CalledBy. The workflow work-item actions name the acting user in their own member (see 10. Workflow Action Service).

Preview. Every write operation's request accepts an optional PreviewMode boolean. Operations that implement a preview validate the request and post nothing when it is true; every other operation refuses PreviewMode: true with ErrorCode PreviewUnsupported before it reads or writes anything. See 30. Posting Preview.

Cross-reference keys. Request contracts that take a D365 id also accept an ExternalSystem member on the request header and an <Id>ExternalKey member next to each id they cover (for example SalesOrderIdExternalKey, line ItemIdExternalKey). The service replaces the key with the D365 id it names, in the request's legal entity, before its own lookups. Line keys use the header's ExternalSystem. Only alternate keys resolve; a key that matches no record or more than one, or that names a different record than an id sent with it, fails the request as ValidationFailed (the price inquiry included). Batch operations accept the same members on each item. The key members are listed in each operation's field table below; see Cross-reference keys for setup and the full list.

Common Response Format​

The posting and action operations return MGCLatticeOrderOperationResponseContract. The bulk (*Batch), status query, async, price inquiry, trade agreement, database access and DMF configuration operations return the contracts described in their own sections.

{
"Success": true,
"Status": 3,
"ErrorCode": 0,
"IsRetryable": false,
"Message": "Sales order SO-000123 confirmed with confirmation SO-000123-1.",
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"ExecutionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"DocumentId": "SO-000123",
"PostedDocumentId": "SO-000123-1",
"StartDateTimeUtc": "2026-01-15T10:30:00.000Z",
"EndDateTimeUtc": "2026-01-15T10:30:01.234Z",
"DurationMs": 1234,
"Errors": [],
"Warnings": [],
"InformationalMessages": [],
"PreviewMode": false,
"PreviewApplied": false,
"PreviewFidelity": 0
}
FieldTypeDescription
Successbooleantrue if the operation completed without errors
Statusenum MGCLatticeServiceCallStatusLifecycle status. Serialized as the enum's integer value (e.g. 3 = Succeeded, 4 = Failed, 2 = Processing). See MGCLatticeServiceCallStatus.
ErrorCodeenum MGCLatticeServiceErrorCodeMachine-readable error classification. None on success; a stable code (e.g. ValidationFailed, DocumentNotFound, InvalidStatus, TransientRuntime) on failure. Serialized as the enum's integer value (e.g. 0 = None, 1 = ValidationFailed). Use this - not the localized Message - for programmatic routing/retry decisions. See MGCLatticeServiceErrorCode.
IsRetryablebooleantrue when the caller may safely retry the same request. false for business/validation rejections that will fail again unchanged; true for transient runtime faults and RequestInProgress.
MessagestringHuman-readable result description
CorrelationIdGUIDEchoed from the request
ExecutionIdGUIDServer-generated unique ID for this execution
RequestIdGUIDEchoed request identifier from the caller
DocumentIdstringPrimary document ID produced or affected by the operation (e.g., journal number, order number)
PostedDocumentIdstringNumber of the document the operation produced: the confirmation, packing slip, product receipt, invoice, journal or created order. Empty when the operation produces no numbered document. It is stored with the idempotency claim, so a repeated request with the same RequestId returns it again.
StartDateTimeUtcdatetimeServer-side start time
EndDateTimeUtcdatetimeServer-side completion time
DurationMsintegerElapsed wall-clock time in milliseconds, measured with millisecond precision (captured via .NET tick stamps at operation start, so sub-second calls report their true duration rather than 0)
Errorsstring[]Error messages. Populated only on failure (Success=false); includes captured D365 infolog error lines. Empty on success.
Warningsstring[]Non-fatal warning messages. On success, posting-engine infolog output is captured here - including any error-severity lines, which are routed to Warnings so Errors stays consistent with Success=true.
InformationalMessagesstring[]Informational/diagnostic messages, including posting-engine Info infolog lines captured on success.

Posting Preview response block​

Every response carries three preview members. On a normal call they are false, false and 0 (None). See 30. Posting Preview for how a preview is requested.

FieldTypeDescription
PreviewModebooleantrue when the request asked for a preview (also on the PreviewUnsupported refusal of an operation without a preview)
PreviewAppliedbooleantrue when the preview completed cleanly: the request was validated, nothing was posted, and no idempotency claim or open transaction was left behind. A self-check failure sets it to false and adds a warning to Warnings.
PreviewFidelityenum MGCLatticePreviewFidelity0 = None (not a preview), 1 = ValidationOnly (the request was validated without posting).

Status Enums​

Service responses and tracking records carry their lifecycle state as a D365 enum rather than a free-form string. Service operation JSON responses carry the enum's integer value (the Numeric column); OData $metadata and payloads use the member name.

MGCLatticeServiceCallStatus (enum)​

Used by MGCLatticeOrderOperationResponseContract.Status (the common response Status), MGCLatticeBulkOperationResponseContract.Status, MGCLatticeBulkItemResultContract.Status, and the MGCLatticeServiceCallLog table / MGCLatticeServiceCallLogEntity OData entity.

ValueNumericDescription
None0Unset / default
Processing2Execution in progress; also the status of a RequestInProgress answer
Succeeded3Completed successfully
Failed4Completed with errors
PartialSuccess6Bulk operations only (MGCLatticeBulkOperationResponseContract.Status): some items succeeded and some failed

MGCLatticeServiceCallStatus and MGCLatticeAsyncOperationStatus share one value table: 0 None, 1 Queued (async only), 2 Processing, 3 Succeeded, 4 Failed, 6 PartialSuccess (bulk only), 7 NotFound (async status query only). A client can map Status with one table for every response.

MGCLatticeServiceErrorCode (enum)​

Used by MGCLatticeOrderOperationResponseContract.ErrorCode (the common response ErrorCode), MGCLatticeBulkItemResultContract.ErrorCode, and the MGCLatticeServiceCallLog table / MGCLatticeServiceCallLogEntity OData entity. It is the stable, machine-readable failure classification that enterprise middleware (APIM, Logic Apps, Service Bus dead-lettering) can route and make retry decisions on without parsing localized message text. Service operation JSON responses carry the integer value (the Numeric column); OData $metadata and payloads use the member name.

ValueNumericRetryableDescription
None0-No error (success)
ValidationFailed1NoRequest failed common/input validation (e.g. missing RequestId, an unknown LegalEntityId, an external key that does not resolve, an empty item of a bulk request)
DocumentNotFound2NoThe referenced document/journal/asset does not exist in the legal entity
InvalidStatus3NoThe document is in a state that does not permit the requested operation
BusinessRule4NoThe business processing failed after the request was accepted, for example D365 refused to create or post the document
DimensionValueNotFound5NoA supplied financial dimension/account value could not be resolved
TransientRuntime6YesA CLR/runtime (infrastructure) fault was caught; safe to retry with backoff
DuplicateRequest7NoThe RequestId already belongs to a different operation, of the same or another service (see Duplicate RequestId); the operation does not run. Send a new RequestId
RequestInProgress8YesAn identical RequestId is currently being processed; retry once it completes (the request is not executed a second time)
RequestNeedsReview9NoAn earlier attempt with this RequestId stopped without a result and was not run again; check whether it posted before resubmitting
PreviewUnsupported10NoThe request asked for a posting preview of an operation that cannot be previewed
ConfigurationMissing11NoSetup the operation needs is missing (for example a number sequence or a chart of accounts)
LicenseNotValid12YesThe product license is not valid; the request runs once the license is renewed
UnexpectedError13NoAn exception type no specific handler covers (for example an update conflict that could not be recovered). The message reads "Operation <name> failed due to an unexpected error."
AccessDenied14NoThe caller holds no privilege for the operation (async submit and dispatch, DB access, test console), lacks a Lattice operation the journal it posts needs (journal posting), or may not file expenses for the worker (expense reports)
OperationDisabled15NoAn administrator switched the operation off (async operation registry)

MGCLatticeServiceErrorCategory (enum)​

The coarse triage category derived from the error code, stored on dead-letter rows and file-ingestion segments (ErrorCategory).

ValueNumericError codes
None0None only
Connection1TransientRuntime
Format2ValidationFailed, PreviewUnsupported
Data3DocumentNotFound, InvalidStatus, BusinessRule, DimensionValueNotFound, DuplicateRequest, RequestInProgress, RequestNeedsReview, UnexpectedError
Configuration4ConfigurationMissing, LicenseNotValid, AccessDenied, OperationDisabled

MGCLatticeAsyncOperationStatus (enum)​

Used by MGCLatticeAsyncOperationStatusContract.Status, MGCLatticeAsyncOperationResponseContract.Status, and the MGCLatticeAsyncOperationTracking table / MGCLatticeAsyncOperationTrackingEntity OData entity.

ValueNumericDescription
None0Unset / default
Queued1Submitted, awaiting batch pickup
Processing2Running in the batch framework
Succeeded3Completed successfully
Failed4Completed with errors
NotFound7No tracking record found for the supplied tracking ID (status query answer only; never stored)

Log Level Enum​

The three diagnostic log tables (MGCLatticeFileIngestLog, MGCLatticeODataRefreshLog and MGCLatticeServiceMetadataRefreshLog, the service-metadata discovery refresh log) share one severity enum, MGCLatticeLogLevel (field EDT MGCLatticeLogLevelEdt):

ValueNumericDescription
Info0Informational message
Warning1Non-fatal warning
Error2Error condition

Both metadata-discovery refresh logs (MGCLatticeODataRefreshLog and MGCLatticeServiceMetadataRefreshLog) are populated by instrumented, catch-and-continue discovery pipelines. The clear runs in its own committed transaction; discovery then runs outside any transaction so per-element try/catch handlers genuinely fire (in X++, an exception inside an active ttsBegin/ttsCommit bypasses inner catches). Each element - for OData: entity / field / method / parameter; for services: service group / service / operation / contract class - is processed under its own handler that names the failing element and a step (e.g. reading service metadata for X, flushing N service records for group Y), captures the CLR exception detail or infolog text, then continues with the next element. A run-level trap (outside any transaction) records an Error row naming the run step and re-throws so the batch is still reported as failed; for the OData pipeline this run-level row is written by the public MGCLatticeODataMetadataDiscovery::logRunError(...) invoked from the batch run(). Log inserts are guarded (bounded columns truncated, logger never throws) so a logging failure cannot mask the original error, and each stage emits an Info summary counter row (X processed, Y failed). Filter LogLevel = Error to pinpoint the failing element and step.

Rate Limiting and Throttling​

D365 Finance & Operations applies standard platform-level priority-based throttling. When the server is under heavy load, requests may receive HTTP 429 (Too Many Requests) responses with a Retry-After header. Callers should implement exponential backoff and retry logic for 429 responses.

To minimize round-trips and reduce throttling exposure for high-volume integrations, use the batch operation variants (see 19. Bulk Operations). A single batch call processes multiple documents in one HTTP request, which is significantly more efficient than issuing individual calls per document.


1. Sales Order Posting Service​

Service: MGCLatticeSalesOrderPostingService Service Group: MGCLatticeAccountsReceivableServiceGroup

Posting with lines. A request without Lines posts the whole order. With Lines, only the selected lines post, each for its Qty; a line is selected unless it sends IsSelected: false; the other order lines are left as they were. A request line names its order line by LineNum, or by ItemId (plus InventDimId) when exactly one line of that item still has a quantity to post; an ItemId or InventDimId sent with a LineNum must match that line. Qty must be greater than zero and no more than what is left to post on the line (for an invoice, the quantity not yet invoiced). A request whose lines are all unselected, or a line that is empty, names no line or an unknown line, is ambiguous, or names a line another request line already names, is refused with ValidationFailed before anything is posted.

Document numbers. Sales confirmation, packing slip and invoice numbers come from their number sequences. DocumentId is the sales order number; PostedDocumentId is the posted confirmation, packing slip or invoice number, and a repeated request with the same RequestId returns it again. The success message also names it (for example Invoice CIV-000123 posted for sales order SO-000123.). An operation that posts nothing fails instead of answering success. A request that names no sales order (no SalesOrderId and no SalesOrderIdExternalKey that resolves) fails with ValidationFailed (SalesOrderId is required.).

Preview. The confirmation, packing slip and invoice operations accept PreviewMode: true: the request is validated (order and lines resolved) and nothing is posted. cancelSalesPackingSlip has no preview and refuses it with PreviewUnsupported.

Confirmation with lines. A confirmation leaves the order lines' deliver-now quantities as it found them; packing slips and invoices reset the deliver-now quantities of the lines they post, as the standard posting does.

Line Contract: MGCLatticeSalesPostingLineContract

FieldJSON KeyTypeRequiredDescription
Line NumberLineNumdecimalOne of LineNum / ItemIdThe order line's line number
Item IDItemIdstringOne of LineNum / ItemIdItem number; names the line when LineNum is not sent
Inventory Dimension IDInventDimIdstringNoNarrows an ItemId match; must match the line when sent with LineNum
QuantityQtydecimalYesQuantity to post, greater than zero
SelectedIsSelectedbooleanNoDefaults to true; a line with false is skipped. A request whose lines are all unselected is refused

confirmSalesOrder​

Confirms a sales order by posting a confirmation document.

Request Contract: MGCLatticeSalesOrderConfirmRequestContract

FieldJSON KeyTypeRequiredDescription
Sales Order IDSalesOrderIdstringYesSales order number (e.g., SO-000123)
Sales Order ID keySalesOrderIdExternalKeystringNoThe sales order's alternate key in ExternalSystem, used in place of SalesOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoConfirmation date. Defaults to system date.
LinesLinesMGCLatticeSalesPostingLineContract[]NoThe lines and quantities to post; omit to post the whole order (see Posting with lines)
Preview ModePreviewModebooleanNotrue validates the request without posting
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"SalesOrderId": "SO-000123",
"PostingDate": "2026-01-15"
}
}

postSalesPackingSlip​

Posts a packing slip for a sales order: without Lines, everything not yet delivered; with Lines, the selected lines and quantities. The packing slip number comes from the number sequence and is returned as PostedDocumentId.

Request Contract: MGCLatticeSalesOrderPackingSlipRequestContract

FieldJSON KeyTypeRequiredDescription
Sales Order IDSalesOrderIdstringYesSales order number
Sales Order ID keySalesOrderIdExternalKeystringNoThe sales order's alternate key in ExternalSystem, used in place of SalesOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoPacking slip date. Defaults to system date.
LinesLinesMGCLatticeSalesPostingLineContract[]NoThe lines and quantities to post; omit to post the whole order (see Posting with lines)
Preview ModePreviewModebooleanNotrue validates the request without posting
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"SalesOrderId": "SO-000123",
"PostingDate": "2026-01-15",
"Lines": [
{
"LineNum": 1,
"Qty": 5
}
]
}
}

invoiceSalesOrder​

Posts an invoice for a sales order. Without Lines, an order that has packing slips is invoiced for the packing slip quantities not yet invoiced, and an order without packing slips for its ordered quantity. With Lines, the selected lines and quantities are invoiced. The invoice number comes from the number sequence and is returned as PostedDocumentId.

Request Contract: MGCLatticeSalesOrderInvoiceRequestContract

FieldJSON KeyTypeRequiredDescription
Sales Order IDSalesOrderIdstringYesSales order number
Sales Order ID keySalesOrderIdExternalKeystringNoThe sales order's alternate key in ExternalSystem, used in place of SalesOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoInvoice date. Defaults to system date.
LinesLinesMGCLatticeSalesPostingLineContract[]NoThe lines and quantities to post; omit to post the whole order (see Posting with lines)
Preview ModePreviewModebooleanNotrue validates the request without posting
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"SalesOrderId": "SO-000123",
"PostingDate": "2026-01-15"
}
}

cancelSalesPackingSlip​

Cancels a posted sales packing slip exactly as Sales order > Packing slip journal > Cancel does: the standard packing slip posting runs as a cancellation, reverses the delivery, its inventory transactions and its ledger postings, and keeps the packing slip as a new version with zero quantities. The order lines it delivered are open to deliver again. The operation succeeds only when the packing slip reads as canceled and every order line it delivered is open to deliver again by the delivered quantity; otherwise the cancellation is rolled back and nothing is kept.

Without PackingSlipId, the order's only packing slip that can be canceled is canceled. A packing slip posted for several sales orders at once cannot be canceled for one of them alone. The operation has no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. Like every Lattice operation it is idempotent on RequestId.

Request Contract: MGCLatticeSalesPackingSlipCancelRequestContract

FieldJSON KeyTypeRequiredDescription
Sales Order IDSalesOrderIdstringYesSales order number
Sales Order ID keySalesOrderIdExternalKeystringNoThe sales order's alternate key in ExternalSystem, used in place of SalesOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member. See Cross-reference keys.
Packing Slip IDPackingSlipIdstringNoThe packing slip to cancel. Empty: the order's only packing slip that can be canceled
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"SalesOrderId": "SO-000123",
"PackingSlipId": "PS-000456"
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the sales order; PostedDocumentId is the canceled packing slip number. The message names both (Packing slip PS-000456 of sales order SO-000123 was canceled; its quantities are open to deliver again.).

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No RequestId, LegalEntityId or sales order; several packing slips can be canceled and no PackingSlipId was sent; the packing slip number was posted on several delivery dates; the packing slip also delivers other sales orders
DocumentNotFound (2)An unknown sales order, or the named packing slip is not on the order
InvalidStatus (3)The order has no posted packing slip; the packing slip is already canceled, is invoiced (fully or in part), or the packing slip journal's Cancel is not available for it (drop shipment, open warehouse work, project item requirement, an order type that cannot be corrected)
BusinessRule (4)D365 refused the cancellation; the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: cancelSalesPackingSlipBatch takes a _requests list of MGCLatticeSalesPackingSlipCancelRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations).

Security: high-risk. cancelSalesPackingSlip and its batch are granted only by MGCLatticeAccountsReceivablePackingSlipCancelMaintain (Accounts receivable - cancel sales packing slip (high-risk)), which is in MGCLatticeIntegrationServiceHighRiskDuty; the general accounts receivable privilege MGCLatticeAccountsReceivableServiceMaintain does not grant them.


1a. Sales Order Capture Service​

Service: MGCLatticeSalesOrderCaptureService Service Group: MGCLatticeAccountsReceivableServiceGroup

createSalesOrder​

Creates a sales order (type Sales) for a customer with one or more lines, through the standard AxSalesTable/AxSalesLine defaulting and validation. A request without CustAccount (or its key) or without lines, an empty line, a line without ItemId and a line without a Qty (or with 0) fail with ValidationFailed before anything is created; a missing quantity is never defaulted. A CustAccount that names no customer in the legal entity returns DocumentNotFound. DocumentId and PostedDocumentId are the created sales order number. A repeat of the same RequestId returns the order the first call created and creates no second order. The operation has no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs.

Request Contract: MGCLatticeCreateSalesOrderRequestContract

FieldJSON KeyTypeRequiredDescription
Customer AccountCustAccountstringYesCustomer the order is for
Customer Account keyCustAccountExternalKeystringNoThe customer's alternate key in ExternalSystem, used in place of CustAccount.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Currency CodeCurrencyCodestringNoOrder currency; the customer's currency when empty
Sales Order IDSalesOrderIdstringNoOrder number to use; the number sequence assigns one when empty
Customer ReferenceCustomerRefstringNoCustomer reference on the header (for example the customer's purchase order number)
LinesLinesMGCLatticeSalesOrderCaptureLineContract[]YesAt least one order line required
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Line Contract: MGCLatticeSalesOrderCaptureLineContract

FieldJSON KeyTypeRequiredDescription
Item IDItemIdstringYesItem number
Item ID keyItemIdExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemId.
QuantityQtydecimalYesOrdered quantity; not 0
UnitUnitIdstringNoSales unit; the item's default when empty
Unit PriceUnitPricedecimalNoUnit sales price; the trade agreement or default price when 0
SiteSiteIdstringNoShip-from site
WarehouseWarehouseIdstringNoShip-from warehouse
Inventory Dimension IDInventDimIdstringNoA pre-resolved inventory dimension; takes precedence over SiteId/WarehouseId
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"CustAccount": "US-001",
"CustomerRef": "PO-88231",
"Lines": [
{ "ItemId": "D0001", "Qty": 5, "SiteId": "1", "WarehouseId": "11" }
]
}
}

createSalesOrderBatch​

Takes a _requests list of MGCLatticeCreateSalesOrderRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations); each order is created independently under its own RequestId.


2. Purchase Order Posting Service​

Service: MGCLatticePurchaseOrderPostingService Service Group: MGCLatticeAccountsPayableServiceGroup

Posting with lines. On postPurchasePackingSlip and invoicePurchaseOrder, Lines (MGCLatticePurchPostingLineContract, the same members as the sales line contract, IsSelected defaulting to true) follow the sales rules: without Lines the whole order posts; with Lines only the selected lines post, each for its Qty, named by LineNum (the purchase line's line number) or by an ItemId that matches exactly one line with a quantity left to post. Qty must be greater than zero and no more than what is left to post. Invalid lines are refused with ValidationFailed before anything is posted.

Document numbers. The product receipt and invoice are posted under the PackingSlipId and InvoiceId the request sends; both are required. DocumentId is the purchase order number; PostedDocumentId is the posted confirmation, product receipt or invoice number, and a repeated request with the same RequestId returns it again. An operation that posts nothing fails instead of answering success. A request that names no purchase order (no PurchaseOrderId and no PurchaseOrderIdExternalKey that resolves) fails with ValidationFailed.

Preview. The purchase operations have no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs.

confirmPurchaseOrder​

Confirms a purchase order. A confirmation always covers the whole order: the standard purchase order confirmation takes no line or quantity selection, so a request that sends Lines is refused with ValidationFailed (A purchase order confirmation always covers the whole order: send the request without Lines.). PostedDocumentId is the confirmation number.

Request Contract: MGCLatticePurchaseOrderConfirmRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase Order IDPurchaseOrderIdstringYesPurchase order number
Purchase Order ID keyPurchaseOrderIdExternalKeystringNoThe purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoConfirmation date. Defaults to system date.
LinesLinesMGCLatticePurchPostingLineContract[]NoNot accepted: a request with lines is refused (the whole order is confirmed)
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"PurchaseOrderId": "PO-000456",
"PostingDate": "2026-01-15"
}
}

postPurchasePackingSlip​

Posts a product receipt (packing slip) for a purchase order: without Lines, everything not yet received; with Lines, the selected lines and quantities. A request without PackingSlipId is refused. PostedDocumentId is the posted product receipt number.

Request Contract: MGCLatticePurchaseOrderPackingReceiptRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase Order IDPurchaseOrderIdstringYesPurchase order number
Purchase Order ID keyPurchaseOrderIdExternalKeystringNoThe purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Packing Slip IDPackingSlipIdstringYesProduct receipt/packing slip number
Posting DatePostingDatedateNoReceipt date. Defaults to system date.
LinesLinesMGCLatticePurchPostingLineContract[]NoThe lines and quantities to post; omit to post the whole order (see Posting with lines)
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"PurchaseOrderId": "PO-000456",
"PackingSlipId": "PR-001",
"PostingDate": "2026-01-15",
"Lines": [
{
"LineNum": 1,
"Qty": 5
}
]
}
}

invoicePurchaseOrder​

Posts an invoice for a purchase order. An order that has product receipts is invoiced from the receipts, for the received quantities not yet invoiced; if the request sends Lines, they must name every line with a received, uninvoiced quantity, each with exactly that quantity, or the request is refused with ValidationFailed. An order without product receipts is invoiced for its ordered quantity, or, with Lines, for the selected lines and quantities. A request without InvoiceId is refused with ValidationFailed. PostedDocumentId is the posted invoice number.

Request Contract: MGCLatticePurchaseOrderInvoiceRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase Order IDPurchaseOrderIdstringYesPurchase order number
Purchase Order ID keyPurchaseOrderIdExternalKeystringNoThe purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Invoice IDInvoiceIdstringYesVendor invoice number
Posting DatePostingDatedateNoInvoice date. Defaults to system date.
LinesLinesMGCLatticePurchPostingLineContract[]NoThe lines and quantities to post; omit to post the whole order (see Posting with lines)
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"PurchaseOrderId": "PO-000456",
"InvoiceId": "VINV-001",
"PostingDate": "2026-01-15"
}
}

cancelPurchaseProductReceipt​

Cancels a posted product receipt exactly as Purchase order > Product receipt journal > Cancel does: the standard product receipt posting runs as a cancellation, reverses the receipt, its inventory transactions and its ledger postings, and keeps the receipt as a new version with zero quantities. The order lines it received are open to receive again. The operation succeeds only when the receipt reads as canceled and every order line it received is open to receive again by the received quantity; otherwise the cancellation is rolled back and nothing is kept.

The purchase order must be confirmed. Without ProductReceiptId, the order's only product receipt that can be canceled is canceled. A product receipt that also receives other purchase orders cannot be canceled for one of them alone.

Request Contract: MGCLatticePurchaseProductReceiptCancelRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase Order IDPurchaseOrderIdstringYesPurchase order number
Purchase Order ID keyPurchaseOrderIdExternalKeystringNoThe purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member. See Cross-reference keys.
Product Receipt IDProductReceiptIdstringNoThe product receipt to cancel. Empty: the order's only product receipt that can be canceled
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"PurchaseOrderId": "PO-000456",
"ProductReceiptId": "PR-001"
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the purchase order; PostedDocumentId is the canceled product receipt number.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No RequestId, LegalEntityId or purchase order; several product receipts can be canceled and no ProductReceiptId was sent; the receipt number was posted on several delivery dates; the receipt also receives other purchase orders
DocumentNotFound (2)An unknown purchase order, or the named product receipt is not on the order
InvalidStatus (3)The order is not confirmed; the order has no posted product receipt; the receipt is already canceled, invoiced (fully or in part), matched to a pending vendor invoice, linked to project item requirements, or the product receipt journal's Cancel is not available for it (intercompany direct delivery, consignment order)
BusinessRule (4)D365 refused the cancellation; the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: cancelPurchaseProductReceiptBatch takes a _requests list of MGCLatticePurchaseProductReceiptCancelRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations).

Security: high-risk. cancelPurchaseProductReceipt and its batch are granted only by MGCLatticeAccountsPayableProductReceiptCancelMaintain (Accounts payable - cancel product receipt (high-risk)), which is in MGCLatticeIntegrationServiceHighRiskDuty; the general accounts payable privilege MGCLatticeAccountsPayableServiceMaintain does not grant them.

postPurchasePrepaymentInvoice​

Posts a vendor prepayment invoice for a purchase order, as Purchase order > Purchase > Prepayment followed by Invoice > Prepayment invoice does. An order without a prepayment first gets the one the request describes: a percentage of the order total or a fixed amount in the order currency, with the procurement category it posts with. Then the prepayment amount still available to invoice is posted as a vendor invoice of type prepayment (vendor advance) under the vendor's invoice number. The invoice posts to the vendor and to the Purchase prepayment inventory posting account. The prepayment and the invoice are created and posted in one transaction: a failed posting leaves neither behind.

On an order that already has a prepayment, leave the prepayment members out (or send the same values): the operation invoices the existing prepayment. A prepayment is changed on the order in D365. The order can then be invoiced as usual, and the prepayment invoice applied to its invoice (Apply prepayment on the vendor invoice).

Request Contract: MGCLatticePurchasePrepaymentInvoiceRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase Order IDPurchaseOrderIdstringYesPurchase order number
Purchase Order ID keyPurchaseOrderIdExternalKeystringNoThe purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member. See Cross-reference keys.
Vendor Invoice NumberVendorInvoiceNumberstringYesThe vendor's invoice number; it becomes the posted invoice number (the standard duplicate checks apply)
Prepayment PercentPrepaymentPercentdecimalOne of PrepaymentPercent / PrepaymentAmount when the order has no prepaymentPercentage of the order total: greater than 0, at most 100
Prepayment AmountPrepaymentAmountdecimalOne of PrepaymentPercent / PrepaymentAmount when the order has no prepaymentFixed amount in the order currency: greater than 0, at most the order total
Prepayment CategoryPrepaymentCategoryNamestringYes, when the order has no prepaymentProcurement category of the prepayment; it must not be the category of an order line
Prepayment Category HierarchyPrepaymentCategoryHierarchyNamestringNoOnly needed when the category name exists in several procurement category hierarchies
Prepayment DescriptionPrepaymentDescriptionstringNoDescription of a new prepayment
Invoice DateInvoiceDatedateNoInvoice date of the prepayment invoice. Defaults as for any vendor invoice
Posting DatePostingDatedateNoPosting date. Defaults to system date.
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"PurchaseOrderId": "PO-000456",
"VendorInvoiceNumber": "PP-0001",
"PrepaymentPercent": 10,
"PrepaymentCategoryName": "Training",
"PostingDate": "2026-01-15"
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the purchase order; PostedDocumentId is the voucher of the posted prepayment invoice. The message names the invoice number, amount and currency, and the voucher (Prepayment invoice PP-0001 of 50.00 USD was posted for purchase order PO-000456 on voucher APINV-000123.).

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No VendorInvoiceNumber; for an order without a prepayment, both or neither of PrepaymentPercent and PrepaymentAmount, or no PrepaymentCategoryName; a value not greater than 0; a percent above 100; a fixed amount above the order total; an unknown or ambiguous category, or one used on the order's lines; values that differ from the order's existing prepayment
DocumentNotFound (2)An unknown purchase order
InvalidStatus (3)The order is not of type Purchase order, is in review or finalized, is intercompany, already has a posted invoice, has a pending prepayment invoice or has nothing left to prepay; the vendor is on hold for invoicing
ConfigurationMissing (11)Posting definitions are enabled in the general ledger parameters (purchase order prepayments are then not available)
BusinessRule (4)The standard posting refused the invoice (for example a duplicate vendor invoice number or no Purchase prepayment posting account); the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: postPurchasePrepaymentInvoiceBatch takes a _requests list of MGCLatticePurchasePrepaymentInvoiceRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations).

Security: granted by MGCLatticeAccountsPayableServiceMaintain with the other purchase order posting operations (not high-risk: it is a standard vendor invoice posting).

Customer prepayments. There is no sales prepayment invoice operation. Record a customer prepayment as a customer payment journal line marked IsPrepayment, optionally against its sales order (see 9. Payment Journal Service).


3. Transfer Order Posting Service​

Service: MGCLatticeTransferOrderPostingService Service Group: MGCLatticeInventoryServiceGroup

Posting with lines. A request without Lines ships everything remaining (or receives everything shipped and not yet received). With Lines (MGCLatticeTransferPostingLineContract: LineNum, ItemId, InventDimId, Qty, IsSelected), only the selected lines post, each for its Qty; a line is selected unless it sends IsSelected: false. A request line matches the transfer line by ItemId plus, when sent, InventDimId and LineNum. A selected line with Qty of 0 or less, a request whose lines are all unselected, and an empty line are refused with ValidationFailed before anything is posted, so a request with lines never ships or receives the whole order. A line that names no transfer line fails with DocumentNotFound.

Document numbers. DocumentId is the transfer order number; PostedDocumentId is the voucher of the shipment or receipt journal the operation posted, and a repeated request with the same RequestId returns it again. An update that posts no journal fails instead of answering success. A request that names no transfer order fails with ValidationFailed (TransferOrderId is required.).

Preview. The transfer operations have no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs.

shipTransferOrder​

Ships a transfer order (creates the shipment journal).

Request Contract: MGCLatticeTransferOrderShipRequestContract

FieldJSON KeyTypeRequiredDescription
Transfer Order IDTransferOrderIdstringYesTransfer order number
Transfer Order ID keyTransferOrderIdExternalKeystringNoThe transfer order's alternate key in ExternalSystem, used in place of TransferOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoShip date. Defaults to system date.
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
LinesLinesMGCLatticeTransferPostingLineContract[]NoThe lines and quantities to ship; omit to ship everything remaining. A line also accepts ItemIdExternalKey (released product) and LineNumExternalKey (transfer order line; it also fills in the line's item), resolved with the header's ExternalSystem.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"TransferOrderId": "TO-000789",
"PostingDate": "2026-01-15"
}
}

receiveTransferOrder​

Receives a shipped transfer order.

Request Contract: MGCLatticeTransferOrderReceiveRequestContract

FieldJSON KeyTypeRequiredDescription
Transfer Order IDTransferOrderIdstringYesTransfer order number
Transfer Order ID keyTransferOrderIdExternalKeystringNoThe transfer order's alternate key in ExternalSystem, used in place of TransferOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoReceive date. Defaults to system date.
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
LinesLinesMGCLatticeTransferPostingLineContract[]NoThe lines and quantities to receive; omit to receive everything shipped. A line also accepts ItemIdExternalKey (released product) and LineNumExternalKey (transfer order line; it also fills in the line's item), resolved with the header's ExternalSystem.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"TransferOrderId": "TO-000789",
"PostingDate": "2026-01-15"
}
}

4. Inventory Journal Posting Service​

Service: MGCLatticeInventoryJournalPostingService Service Group: MGCLatticeInventoryServiceGroup

The movement, adjustment, counting and transfer operations use the same request contract. The service validates that the journal name matches the expected journal type, and every line must name an existing item; an empty line or an unknown ItemId is refused with ValidationFailed. The BOM, tag counting and ownership change operations have request contracts of their own (see postBOMJournal, postTagCountingJournal and postOwnershipChangeJournal); on these three JournalNameId is optional and defaults to the inventory parameters' journal name for the type.

The journal is created and then posted. Success is reported only when the journal is posted; DocumentId and PostedDocumentId are the journal number (the BOM, tag counting and ownership change operations describe their own PostedDocumentId). The operations have no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. If the operation fails after creating the journal, the unposted journal is deleted, so a failed request leaves no journal behind and a retry with the same RequestId creates it again.

In a counting journal (postCountingJournal), each line's Qty is the counted quantity: the line posts the difference between the counted quantity and the on-hand quantity at the posting date, as the counting journal page does.

postMovementJournal / postAdjustmentJournal / postCountingJournal / postTransferJournal​

Request Contract: MGCLatticeInventJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesInventory journal name (must match operation type)
DescriptionDescriptionstringNoJournal header description
Posting DatePostingDatedateNoTransaction date. Defaults to system date.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
LinesLinesMGCLatticeInventJournalLineContract[]YesAt least one journal line required
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Line Contract: MGCLatticeInventJournalLineContract

FieldJSON KeyTypeRequiredDescription
Item IDItemIdstringYesItem number
Item ID keyItemIdExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemId.
Inventory Dimension IDInventDimIdstringNoInventory dimension ID
QuantityQtydecimalYesJournal line quantity; in a counting journal, the counted quantity
Cost PriceCostPricedecimalNoUnit cost price
Cost AmountCostAmountdecimalNoTotal cost amount
Offset Main Account IDOffsetMainAccountIdstringNoCounter-account (main account) for the line. A movement journal line needs one unless the item's inventory posting profile supplies the "Inventory expenditure, profit/loss" accounts. An account that does not resolve in the legal entity's chart of accounts fails the request with DimensionValueNotFound
To Inventory Dim IDToInventDimIdstringNoTarget dimension (transfer journals only)
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "IMov",
"Description": "Integration movement journal",
"PostingDate": "2026-01-15",
"Lines": [
{
"ItemId": "A0001",
"Qty": 10.0,
"CostPrice": 25.50,
"InventDimId": "000001"
}
]
}
}

postBOMJournal​

Posts a BOM journal: each line reports a BOM item as finished and consumes the components of its BOM outside production, as Inventory management > Journal entries > Item journals > Bill of materials > Report as finished, then Post, does. The receipt line and the component issue lines (phantom components exploded, cost from the components) are created by the standard Report as finished; the journal is then posted. A journal that was created and could not be posted is deleted again.

Request Contract: MGCLatticeInventBOMJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringNoA BOM journal name. Empty: the BOM journal name of the inventory parameters
DescriptionDescriptionstringNoJournal description. Defaults to the journal name's
Posting DatePostingDatedateNoThe date the items are reported as finished; it also selects the BOM version. Defaults to system date.
External SystemExternalSystemstringNoThe external system of the lines' ...ExternalKey members. See Cross-reference keys.
LinesLinesMGCLatticeInventBOMJournalLineContract[]YesOne line per BOM item
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Line Contract: MGCLatticeInventBOMJournalLineContract

FieldJSON KeyTypeRequiredDescription
Item IDItemIdstringYesThe BOM item: stocked, and one that can be produced
Item ID keyItemIdExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemId.
QuantityQtydecimalYesQuantity reported as finished, in the inventory unit; greater than zero
Inventory Dimension IDInventDimIdstringNoReceipt dimensions
SiteSiteIdstringNoReceipt site, on top of InventDimId
WarehouseWarehouseIdstringNoReceipt warehouse, on top of InventDimId. A warehouse without a site takes its own site; dimensions left open are the item's defaults for the site, as Report as finished fills them in
BOM IDBOMIdstringNoThe BOM to consume; it must be a BOM of the item. Empty: the item's active BOM version for the date, quantity and site
BOM ID keyBOMIdExternalKeystringNoThe BOM's alternate key in ExternalSystem, used in place of BOMId.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "IBOM",
"Description": "Kit assembly",
"PostingDate": "2026-01-15",
"Lines": [
{ "ItemId": "D0007", "Qty": 1, "SiteId": "1", "WarehouseId": "11" }
]
}
}

Response: DocumentId and PostedDocumentId are the posted BOM journal. The message counts the item lines reported as finished and the component lines consumed (BOM journal 00123 posted: 1 item line(s) reported as finished and 2 component line(s) consumed.). Posting warnings are in Warnings.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)JournalNameId unknown or not a BOM journal name; no lines, an empty line, an unknown item, Qty of 0 or less, an unknown InventDimId, site or warehouse, or a warehouse of another site; an item that cannot be produced or is not stocked; a BOMId that is not a BOM of the item; no active BOM version
ConfigurationMissing (11)No JournalNameId and no default BOM journal name in the inventory parameters
BusinessRule (4)Report as finished raised warnings (or found a circular BOM), so the standard would not post the journal; or the posting was refused (for example negative inventory or missing ledger accounts), with the standard messages in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: postBOMJournalBatch takes a _requests list of MGCLatticeInventBOMJournalPostRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations).

postTagCountingJournal​

Posts a tag counting journal (Inventory management > Journal entries > Item counting > Tag counting). As in the standard, posting the tags does not change on-hand: it creates a counting journal (named by the counting journal name of the inventory parameters) with one line per item and counted dimensions, counted quantity = the sum of the used tags, and leaves it open for review; posting that counting journal adjusts on-hand. The operation does the same and returns the counting journal. With PostCountingJournal: true it also posts the counting journal, in the same transaction as the tags: either both are posted or neither. The journal counts by the dimensions the tags give (for example site and warehouse), which the counting journal inherits.

Request Contract: MGCLatticeInventTagJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringNoA tag counting journal name. Empty: the tag counting journal name of the inventory parameters
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoThe counting date; the counted quantities are compared with on-hand at this date. Defaults to system date.
Post Counting JournalPostCountingJournalbooleanNotrue also posts the counting journal. Default false: the counting journal is left open for review, as in the standard
External SystemExternalSystemstringNoThe external system of the lines' ...ExternalKey members. See Cross-reference keys.
LinesLinesMGCLatticeInventTagJournalLineContract[]YesOne line per tag
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Line Contract: MGCLatticeInventTagJournalLineContract

FieldJSON KeyTypeRequiredDescription
Tag NumberTagNumberstringYesTag number, unique in the request (compared without regard to case), at most 10 characters. A longer number is refused, never shortened
Tag StatusTagStatusintegerNoSent as a number: 1 Used, 2 Voided, 3 Missing. Empty or 0: Used
Item IDItemIdstringUsed tagsThe counted item. Not allowed on a voided or missing tag
Item ID keyItemIdExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemId.
QuantityQtydecimalUsed tagsCounted quantity, in the inventory unit; 0 or more. Not allowed on a voided or missing tag
Inventory Dimension IDInventDimIdstringNoWhere the tag was counted
SiteSiteIdstringNoSite where the tag was counted, on top of InventDimId
WarehouseWarehouseIdstringNoWarehouse where the tag was counted, on top of InventDimId
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "ITag",
"PostingDate": "2026-01-15",
"PostCountingJournal": false,
"Lines": [
{ "TagNumber": "T-0001", "ItemId": "D0001", "Qty": 12, "SiteId": "1", "WarehouseId": "11" },
{ "TagNumber": "T-0002", "ItemId": "D0001", "Qty": 8, "SiteId": "1", "WarehouseId": "11" },
{ "TagNumber": "T-0003", "TagStatus": 2 }
]
}
}

Response: DocumentId is the posted tag counting journal; PostedDocumentId is the counting journal it created (empty when no tag counted an item). The message says whether the counting journal was posted or is open for review (Tag counting journal 00124 posted (3 tag(s)). Counting journal 00125 was created with the counted quantities and is open for review.).

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)JournalNameId unknown or not a tag counting journal name; no lines, an empty line, no TagNumber, a TagNumber longer than 10 characters or used twice in the request; a used tag without an item; a voided or missing tag with an item or a quantity; an unknown item; a Qty below 0; unknown dimensions
ConfigurationMissing (11)No JournalNameId and no default tag counting journal name; no default counting journal name in the inventory parameters (posting the tags needs it)
BusinessRule (4)A tag the standard refuses (for example a stopped item), or the posting was refused; the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: postTagCountingJournalBatch takes a _requests list of MGCLatticeInventTagJournalPostRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations).

postOwnershipChangeJournal​

Posts a consignment inventory ownership change journal (Inventory management > Journal entries > Item journals > Inventory ownership change): vendor-owned stock becomes the legal entity's own. The standard posting moves the quantity from the vendor's owner dimension to the legal entity's owner without a financial impact, and creates, confirms and receives a purchase order per vendor for it, which the vendor then invoices.

Request Contract: MGCLatticeInventOwnershipJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringNoAn ownership change journal name. Empty: the ownership change journal name of the inventory parameters (USMF has none set: send IOwner)
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoDate of the ownership change; the purchase order is received on it. Defaults to system date.
External SystemExternalSystemstringNoThe external system of the lines' ...ExternalKey members. See Cross-reference keys.
LinesLinesMGCLatticeInventOwnershipJournalLineContract[]YesAt least one line required
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Line Contract: MGCLatticeInventOwnershipJournalLineContract

FieldJSON KeyTypeRequiredDescription
Item IDItemIdstringYesThe item; it must track the Owner dimension
Item ID keyItemIdExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemId.
QuantityQtydecimalYesQuantity, in the inventory unit; greater than zero
Vendor AccountVendAccountstringYes, unless InventDimId carries the ownerThe vendor that owns the stock now (its inventory owner)
Vendor Account keyVendAccountExternalKeystringNoThe vendor's alternate key in ExternalSystem, used in place of VendAccount.
Inventory Dimension IDInventDimIdstringNoDimensions of the vendor-owned stock
SiteSiteIdstringNoSite of the vendor-owned stock, on top of InventDimId
WarehouseWarehouseIdstringNoWarehouse of the vendor-owned stock, on top of InventDimId. Open dimensions are the item's defaults
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "IOwner",
"PostingDate": "2026-01-15",
"Lines": [
{ "ItemId": "M9211CI", "Qty": 1, "VendAccount": "US-104", "SiteId": "5", "WarehouseId": "51" }
]
}
}

Response: DocumentId is the posted ownership change journal; PostedDocumentId is the purchase order the posting created (the first one, when the journal covers several vendors). The message lists every purchase order.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)JournalNameId unknown or not an ownership change journal name; no lines, an empty line, an unknown item, Qty of 0 or less, an item without the Owner dimension, unknown dimensions, an unknown vendor, a vendor without an inventory owner, VendAccount and InventDimId naming different owners, no owner, or the legal entity itself as the owner
ConfigurationMissing (11)The consignment configuration key (ConsignmentInbound) is off; no JournalNameId and no default ownership change journal name
BusinessRule (4)The posting was refused (for example not enough vendor-owned stock, or the purchase order could not be created); the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: postOwnershipChangeJournalBatch takes a _requests list of MGCLatticeInventOwnershipJournalPostRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations).

Security: the seven journal operations and their batches are granted by MGCLatticeInventoryServiceMaintain (Inventory integration service operations).


4a. Inventory Cost Service​

Service: MGCLatticeInventoryCostService Service Group: MGCLatticeInventoryServiceGroup Security: MGCLatticeInventoryCostActivateMaintain (high-risk privilege) grants Invoke on activatePendingPrices and activatePendingPricesBatch. It is in MGCLatticeIntegrationServiceHighRiskDuty, so only the integration administrator role holds it; the general inventory privilege MGCLatticeInventoryServiceMaintain does not grant it. calculateItemCosts and its batch are granted by MGCLatticeInventoryCostCalculateMaintain (see calculateItemCosts).

activatePendingPrices activates the pending item prices of a costing version: the new standard costs (and, on request, pending purchase and sales prices) become the active prices. It is the service equivalent of activating pending prices in D365 (Activate on the Costing versions page, Activate pending price(s) on an item's Item price page). The operation runs the standard activation (InventItemPriceActivationJob) in one transaction, so either every eligible pending price is activated or, when one fails, none is. Activating a standard cost revalues the item's on-hand inventory at the new cost and posts the revaluation to the general ledger, which is why the operation is high-risk.

activatePendingPrices​

A pending price is activated when it is the newest one of its item, price type and price dimensions, is dated today (in the calling user's time zone) or earlier, and passes the standard activation checks. A standard costing version with a fixed From date requires its pending prices to carry that date (USMF version 10: 2018-01-01).

  • Without ItemIds, every eligible pending price of the version is activated; with ItemIds, only the pending prices of those items.
  • When none of ActivateCostPrice, ActivatePurchasePrice and ActivateSalesPrice is set, cost prices only are activated (the new standard costs).
  • ActivateCostCategoryPrices also activates the version's pending routing cost category prices and cost sheet calculation factors. These apply to the whole version, so the member cannot be combined with ItemIds.
  • A request with nothing eligible to activate (no pending price of the requested price types and items dated today or earlier, and ActivateCostCategoryPrices not set) is refused with BusinessRule.
  • The operation has no preview: PreviewMode: true is refused with PreviewUnsupported before any other check. Like every Lattice operation it is idempotent on RequestId (a repeat returns the recorded response and activates nothing again) and license-gated. A large costing version can outlast a synchronous call, so the operation can also be queued with submitAsyncOperation (see 21. Async Operations).

Request Contract: MGCLatticePendingPriceActivationRequestContract

FieldJSON KeyTypeRequiredDescription
Costing Version IDCostingVersionIdstringYesThe costing version whose pending prices are activated. Must exist in the legal entity (DocumentNotFound otherwise) and not be blocked for activation (InvalidStatus otherwise).
Activate Cost PriceActivateCostPricebooleanNoActivate pending cost prices. When none of the three price-type members is set, cost prices are activated.
Activate Purchase PriceActivatePurchasePricebooleanNoActivate pending purchase prices
Activate Sales PriceActivateSalesPricebooleanNoActivate pending sales prices
Activate Cost Category PricesActivateCostCategoryPricesbooleanNoAlso activate the version's pending routing cost category prices and cost sheet calculation factors. They apply to the whole version: sent together with ItemIds, the request is refused with ValidationFailed.
Skip If Equal Price ExistsSkipIfEqualPriceExistsbooleanNoLeave a pending price that equals the active price pending
Item IDsItemIdsstring[]NoActivate only the pending prices of these items. Empty or absent: every eligible pending price of the version. An unknown item is refused with ValidationFailed.
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"CostingVersionId": "10",
"ActivateCostPrice": true,
"ItemIds": ["M0001"]
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the costing version. PostedDocumentId is the voucher of the on-hand inventory revaluation, and is empty when no on-hand inventory was revalued (for example an item with nothing on hand, or only purchase or sales prices activated). The message names how many prices were activated and for which items:

OutcomePostedDocumentIdMessage
Prices activated, on-hand inventory revaluedThe revaluation voucherActivated 1 pending price(s) in costing version 10: M0001. On-hand inventory was revalued on voucher IAV-000041.
Prices activated, nothing revaluedEmptyActivated 2 pending price(s) in costing version 10: M0001, M0004.
No item price activatedEmptyNo item price was activated in costing version 10: every eligible pending price equals the active price, or only cost category prices and calculation factors were pending.

The last outcome is a success too: with SkipIfEqualPriceExists every eligible pending price equalled the active price, or ActivateCostCategoryPrices found only cost category prices and calculation factors to activate.

{
"Success": true,
"Status": 3,
"ErrorCode": 0,
"IsRetryable": false,
"Message": "Activated 1 pending price(s) in costing version 10: M0001. On-hand inventory was revalued on voucher IAV-000041.",
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"ExecutionId": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"DocumentId": "10",
"PostedDocumentId": "IAV-000041",
"StartDateTimeUtc": "2026-10-07T14:02:11.000Z",
"EndDateTimeUtc": "2026-10-07T14:02:13.512Z",
"DurationMs": 2512,
"Errors": [],
"Warnings": [],
"InformationalMessages": [],
"PreviewMode": false,
"PreviewApplied": false,
"PreviewFidelity": 0
}

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No CostingVersionId (CostingVersionId is required.), an empty RequestId or LegalEntityId, an unknown legal entity, ActivateCostCategoryPrices together with ItemIds (Cost category prices and calculation factors apply to the whole costing version: send ActivateCostCategoryPrices without ItemIds.), or an unknown item in ItemIds (Item 'X' was not found.)
DocumentNotFound (2)Costing version X was not found in legal entity Y.
InvalidStatus (3)Costing version X is blocked for activation.
BusinessRule (4)Nothing eligible to activate (Costing version X has no pending price dated <today> or earlier for the requested price types and items.), or the standard activation refused a price; nothing is activated and the reason is in Errors
TransientRuntime (6)Pending price activation failed due to an integration runtime error.; IsRetryable true
DuplicateRequest (7)The RequestId was first used for another operation
LicenseNotValid (12)The license verdict is adverse; IsRetryable true

activatePendingPricesBatch​

Takes a _requests list of MGCLatticePendingPriceActivationRequestContract (for example one per legal entity or costing version) and returns MGCLatticeBulkOperationResponseContract with one result per item (see 19. Bulk Operations). Each item runs exactly as activatePendingPrices, in its own transaction and with its own RequestId, so a failed item does not undo the activation of another. A missing or empty list fails with no results; an empty (null) item fails as its own item with ValidationFailed. The batch operation is not registered for async execution.

{
"_requests": [
{ "RequestId": "b1c2d3e4-0001-4000-8000-000000000001", "LegalEntityId": "USMF", "CostingVersionId": "10" },
{ "RequestId": "b1c2d3e4-0001-4000-8000-000000000002", "LegalEntityId": "DEMF", "CostingVersionId": "20" }
]
}

calculateItemCosts​

Calculates item costs in a costing version, as Costing versions > Calculation does: the standard item cost calculation rolls up each item's BOM and route costs (and, for an item procured by purchase when the version calculates those, its purchase price) and records the result as the item's pending cost price in the version, dated the calculation date. Nothing is activated, revalued or posted; activatePendingPrices makes the calculated prices active.

  • The calculation uses the costing version's settings, as the calculation dialog does when it is opened from the version: cost prices (and sales prices when the version allows them), the version's profit setting, fallback principle, cost price and purchase price models and rounding, single level for a standard costing version, and the procurement modes the version calculates (BOM calculation, purchase calculation). An existing pending price of the same item, site and date is overwritten.
  • Like the standard, it runs outside a transaction: each item is calculated and recorded on its own, and an item that fails does not stop the others. Without ItemIds the run succeeds when it recorded at least one pending price. With ItemIds every named item must get a pending cost price; otherwise the request fails with BusinessRule naming those items, while the prices calculated for the other items stay recorded (calling again recalculates them).
  • The operation has no preview: PreviewMode: true is refused with PreviewUnsupported before any other check. It is idempotent on RequestId. A whole costing version can outlast a synchronous call, so the operation can also be queued with submitAsyncOperation (see 21. Async Operations).

Request Contract: MGCLatticeItemCostCalculationRequestContract

FieldJSON KeyTypeRequiredDescription
Costing Version IDCostingVersionIdstringYesThe costing version to calculate. Must exist in the legal entity (DocumentNotFound otherwise) and not be blocked (InvalidStatus otherwise; blocking activation does not block calculation)
Site IDSiteIdstringWhen the version has no siteThe site the costs are calculated for. A version restricted to a site calculates for that site: send it or leave it empty
Calculation DateCalculationDatedateNoThe calculation date and from date of the pending prices. Empty: the version's fixed date, else today. A version with a fixed date accepts only that date
Item IDsItemIdsstring[]NoItems to calculate. Empty or absent: every item of the legal entity, as the costing version's Calculation does. An unknown item is refused with ValidationFailed
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"CostingVersionId": "10",
"SiteId": "1",
"ItemIds": ["D0003"]
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the costing version. PostedDocumentId is the calculation number (the BOM calculation the pending price refers to, shown on the pending price and in the calculation results) of the first calculated item in item number order. The message says how many pending prices were calculated, for which site and date, and for which items (the first 25, then how many more): Calculated 1 pending price(s) in costing version 10 for site 1 on 1/1/2018: D0003. Warnings carries the calculation's warnings (no BOM, no route, zero cost price, fallback price used, ...) and the errors of items that could not be calculated; on failure they are in Errors.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No CostingVersionId, an empty RequestId or LegalEntityId, an unknown legal entity; a standard cost conversion version (it is calculated from its conversion); a version that does not allow cost prices; no SiteId for a version without a site, an unknown site, or a SiteId other than the version's site; a CalculationDate other than the version's fixed date; an unknown item in ItemIds
DocumentNotFound (2)Costing version X was not found in legal entity Y.
InvalidStatus (3)Costing version X is blocked, so its item costs cannot be calculated.
ConfigurationMissing (11)The calculation number sequence (BOM parameters) is not set up
BusinessRule (4)The run recorded no pending price, or an item named in ItemIds got no pending cost price; the reasons are in Errors
TransientRuntime (6)Item cost calculation failed due to an integration runtime error.; IsRetryable true
DuplicateRequest (7)The RequestId was first used for another operation
LicenseNotValid (12)The license verdict is adverse; IsRetryable true

Batch: calculateItemCostsBatch takes a _requests list of MGCLatticeItemCostCalculationRequestContract and returns MGCLatticeBulkOperationResponseContract with one result per item (see 19. Bulk Operations). Each item runs exactly as calculateItemCosts. A missing or empty list fails with no results; an empty (null) item fails as its own item with ValidationFailed. The batch operation is not registered for async execution.

Security: MGCLatticeInventoryCostCalculateMaintain (Inventory cost - calculate item costs) grants Invoke on calculateItemCosts and calculateItemCostsBatch. It is in MGCLatticeIntegrationServiceOperationsDuty, not the high-risk duty: the operation records pending prices only and activates, revalues and posts nothing. Activating the calculated prices still needs MGCLatticeInventoryCostActivateMaintain.


5. Production Order Posting Service​

Service: MGCLatticeProductionOrderPostingService Service Group: MGCLatticeProductionServiceGroup

A request without ProdId (and without ProdIdExternalKey) fails with ValidationFailed; a ProdId that names no production order in the legal entity returns DocumentNotFound.

No production operation has a preview: a request with PreviewMode set to true is refused with PreviewUnsupported before anything runs. postPickList, postRouteCard and reportAsFinished return the number of the production journal they posted in PostedDocumentId; the other operations produce no document of their own and leave it empty. DocumentId is the production order on every operation.

The status operations (estimateProductionOrder, scheduleProductionOrder, releaseProductionOrder, startProductionOrder, reportAsFinished, endProductionOrder) run the standard production status update. When the production control parameters do not allow that update from the order's current status, the operation fails with InvalidStatus and names the order's status; it never reports a skipped update as done.

postPickList and postRouteCard validate every line first (a refused line creates no journal), then create a production journal and post it. Success is reported only when the journal is posted. If posting fails, the unposted journal is deleted, so it does not block later status changes of the order and a retry with the same RequestId creates it again. The lines are posted exactly as sent: the automatic report as finished on the last operation and the automatic picking list that the route card form derives from the production parameters are not applied.

estimateProductionOrder / scheduleProductionOrder / releaseProductionOrder​

Simple lifecycle actions that take a production order ID. They take no date: the standard estimation, scheduling and release run with their own defaults.

Request Contract: MGCLatticeProductionOrderActionRequestContract

FieldJSON KeyTypeRequiredDescription
Production IDProdIdstringYesProduction order number
Production ID keyProdIdExternalKeystringNoThe production order's alternate key in ExternalSystem, used in place of ProdId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProdId": "P000001"
}
}

startProductionOrder​

The start applies the start parameters of the order's site (automatic BOM and route consumption), as the standard start does.

Request Contract: MGCLatticeProductionStartRequestContract

FieldJSON KeyTypeRequiredDescription
Production IDProdIdstringYesProduction order number
Production ID keyProdIdExternalKeystringNoThe production order's alternate key in ExternalSystem, used in place of ProdId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoStart date. Defaults to system date.
Start QuantityStartQtydecimalNoQuantity to start. Defaults to the quantity not started yet (scheduled minus started).
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProdId": "P000001",
"PostingDate": "2026-01-15",
"StartQty": 100.0
}
}

postPickList​

Request Contract: MGCLatticeProductionPickListPostRequestContract

FieldJSON KeyTypeRequiredDescription
Production IDProdIdstringYesProduction order number
Production ID keyProdIdExternalKeystringNoThe production order's alternate key in ExternalSystem, used in place of ProdId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoPick list date. Defaults to system date.
LinesLinesMGCLatticeProductionPickListLineContract[]YesAt least one pick list line required

Each line consumes against a production BOM line of the order: the one InventTransId names, otherwise the order's only open BOM line (remaining quantity above zero) for the item. An item with no open BOM line is consumed on a new BOM line (unplanned consumption); an item with more than one open BOM line needs InventTransId. A line with Qty of zero or less, an InventDimId that does not exist, or a lot that is not a BOM line of the order fails with ValidationFailed; an unknown item fails with DocumentNotFound.

Line Contract: MGCLatticeProductionPickListLineContract

FieldJSON KeyTypeRequiredDescription
Item IDItemIdstringYes, unless InventTransId is sentBOM component item number
Item ID keyItemIdExternalKeystringNoThe component's released product's alternate key in ExternalSystem, used in place of ItemId.
QuantityQtydecimalYesConsumption quantity, greater than zero, in the BOM line's unit (the item's BOM unit for a new BOM line)
Inventory Dim IDInventDimIdstringNoInventory dimension to consume from
Lot IDInventTransIdstringNoLot id of the production BOM line to consume against
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProdId": "P000001",
"PostingDate": "2026-01-15",
"Lines": [
{
"ItemId": "M0001",
"Qty": 50.0,
"InventDimId": "000001"
}
]
}
}

postRouteCard​

Request Contract: MGCLatticeProductionRouteCardPostRequestContract

FieldJSON KeyTypeRequiredDescription
Production IDProdIdstringYesProduction order number
Production ID keyProdIdExternalKeystringNoThe production order's alternate key in ExternalSystem, used in place of ProdId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoRoute card date. Defaults to system date.
LinesLinesMGCLatticeProductionRouteCardLineContract[]YesAt least one route card line required

Each line reports process time and quantities on a primary operation of the order's route and is defaulted as the route card form does: job type Process, the operation's resource, worker, default dimension, hour and quantity cost categories with their prices, and the executed percentage. A line without OprNum, a line with no hours and no quantities, or an operation that is not on the order's route fails with ValidationFailed.

Line Contract: MGCLatticeProductionRouteCardLineContract

FieldJSON KeyTypeRequiredDescription
Operation NumberOprNumintegerYesRoute operation number
HoursHoursdecimalNoProcess hours. A line needs hours, a good quantity or an error quantity.
Good QuantityGoodQtydecimalNoQuantity completed successfully
Error QuantityErrorQtydecimalNoQuantity with errors
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProdId": "P000001",
"PostingDate": "2026-01-15",
"Lines": [
{
"OprNum": 10,
"Hours": 8.0,
"GoodQty": 100.0,
"ErrorQty": 2.0
}
]
}
}

reportAsFinished​

Request Contract: MGCLatticeProductionReportFinishedRequestContract

FieldJSON KeyTypeRequiredDescription
Production IDProdIdstringYesProduction order number
Production ID keyProdIdExternalKeystringNoThe production order's alternate key in ExternalSystem, used in place of ProdId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoReport date. Defaults to system date.
Good QuantityGoodQtydecimalNoQuantity completed successfully. A report that does not end the job needs a good or an error quantity.
Error QuantityErrorQtydecimalNoQuantity with defects
End JobEndJobbooleanNoThe standard "End job". Default false reports a partial quantity: the order keeps its status and its remaining quantity. True ends the job: the order becomes Reported as finished and its remaining expected receipt is cleared.
Accept ErrorAcceptErrorbooleanNoThe form's "Accept error", used when EndJob is true: end the job even when the order's route jobs or BOM lines have not been reported as finished. Default false stops with "Job ... has not been reported as finished".
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProdId": "P000001",
"PostingDate": "2026-01-15",
"GoodQty": 98.0,
"ErrorQty": 2.0,
"EndJob": true,
"AcceptError": true
}
}

endProductionOrder​

Ends a production order (must be in Reported as finished status). Calculates historical cost as of PostingDate.

Request Contract: MGCLatticeProductionEndRequestContract

FieldJSON KeyTypeRequiredDescription
Production IDProdIdstringYesProduction order number
Production ID keyProdIdExternalKeystringNoThe production order's alternate key in ExternalSystem, used in place of ProdId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoCalculation date of the end. Defaults to system date.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProdId": "P000001",
"PostingDate": "2026-01-15"
}
}

6. Return Order Services​

Returns are two services: sales returns in Accounts receivable, purchase returns in Accounts payable.

ServiceService GroupOperations
MGCLatticeSalesReturnServiceMGCLatticeAccountsReceivableServiceGroupcreateSalesReturn, receiveSalesReturn, creditSalesReturn (+ Batch)
MGCLatticePurchaseReturnServiceMGCLatticeAccountsPayableServiceGroupcreatePurchaseReturn, shipPurchaseReturn, creditPurchaseReturn (+ Batch)

Common rules of the six operations:

  • DocumentId is the return order number; PostedDocumentId is the document the operation produced: the created return order (create), the return packing slip (receive, ship) or the credit note (credit). A repeated request with the same RequestId returns both.
  • A request without the order number (SalesOrderId / PurchaseOrderId, after any external key is resolved) fails with ValidationFailed, naming the member.
  • The operations have no preview: a request with PreviewMode: true is refused with ErrorCode PreviewUnsupported before anything runs, and no idempotency claim is written.

receiveSalesReturn​

Posts a return receipt for a sales return order. Validates that the order is of type ReturnItem, then runs the standard return flow: every open line still awaiting arrival is registered with its disposition code (the return order's Registration step, line → Registered) and the packing slip moves it to Received, which is what creditSalesReturn requires. PostedDocumentId is the return packing slip number.

Request Contract: MGCLatticeSalesReturnReceiveRequestContract

FieldJSON KeyTypeRequiredDescription
Sales order IDSalesOrderIdstringYesSales return order number
Sales order ID keySalesOrderIdExternalKeystringNoThe return order's alternate key in ExternalSystem, used in place of SalesOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoReceipt date. Defaults to system date.
Disposition CodeDispositionCodestringLines without oneApplied at registration. Its action decides the flow: Credit (USMF 11) receives into inventory and leaves the line for the credit note; CreditOnly (21) credits without a receipt; Scrap (61) scraps. Lines that already carry a code keep it.
Preview modePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"SalesOrderId": "001412",
"PostingDate": "2026-01-15",
"DispositionCode": "11"
}
}

creditSalesReturn​

Posts a credit note (invoice) for a sales return order. PostedDocumentId is the credit note (invoice) number.

Request Contract: MGCLatticeSalesReturnCreditRequestContract

FieldJSON KeyTypeRequiredDescription
Sales order IDSalesOrderIdstringYesSales return order number
Sales order ID keySalesOrderIdExternalKeystringNoThe return order's alternate key in ExternalSystem, used in place of SalesOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Posting DatePostingDatedateNoCredit date. Defaults to system date.
Preview modePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported.

createSalesReturn / createPurchaseReturn​

Create a return order - a sales order of type ReturnItem for a customer (createSalesReturn), or a purchase order of type ReturnItem to a vendor (createPurchaseReturn) - with its return lines, through the standard AxSalesTable/AxSalesLine or AxPurchTable/AxPurchLine defaulting and validation. Every line needs a Qty: a line without one (or with 0), and an empty line, fail the request with ValidationFailed before anything is created; a missing quantity is never defaulted. Return quantities are stored negative. DocumentId and PostedDocumentId are the created sales order / purchase order number. The standard purchase order data entity only covers ordinary purchase orders, so createPurchaseReturn is the way to create a return purchase order through the API. Both have a batch variant (createSalesReturnBatch, createPurchaseReturnBatch).

Request Contracts: MGCLatticeCreateSalesReturnRequestContract, MGCLatticeCreatePurchaseReturnRequestContract

FieldJSON KeyTypeRequiredDescription
CustomerCustAccountstringSales: YesCustomer the goods come back from
Customer keyCustAccountExternalKeystringNoSales only. The customer's alternate key in ExternalSystem, used in place of CustAccount.
Return reasonReturnReasonCodeIdstringSales: Yes; purchase: NoHeader return reason code; it applies to every line
Return deadlineReturnDeadlinedateNoSales only
VendorVendAccountstringPurchase: YesVendor the goods go back to
Vendor keyVendAccountExternalKeystringNoPurchase only. The vendor's alternate key in ExternalSystem, used in place of VendAccount.
RMA numberReturnItemNumstringPurchase: YesThe vendor's return authorization (max. 10 characters); F&O does not save a return order without one
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
LinesLinesMGCLatticeReturnLineContract[]YesItemId, Qty (required, not 0; stored negative), and the storage dimensions: SiteId + WarehouseId (or a raw InventDimId). A purchase return ships out of that warehouse, so it must hold the quantity. Sales lines also take DispositionCode. A line also accepts ItemIdExternalKey (the released product's key in the header's ExternalSystem).
Preview modePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported.
{
"_request": {
"RequestId": "5b1f0a3e-8a7c-4d0b-9f2e-6c1d2e3f4a5b",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"VendAccount": "US-101",
"ReturnItemNum": "RMA7788",
"Lines": [ { "ItemId": "D0001", "Qty": 1, "SiteId": "1", "WarehouseId": "11" } ]
}
}

shipPurchaseReturn​

Posts a return shipment (product receipt) for a purchase return order. The order must be of type ReturnItem and confirmed - confirm it with confirmPurchaseOrder first; an unconfirmed order is refused ("must be confirmed before it can be shipped") because F&O posts no product receipt for it. PostedDocumentId is the return shipment number.

Request Contract: MGCLatticePurchaseReturnShipRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase order IDPurchaseOrderIdstringYesPurchase return order number
Purchase order ID keyPurchaseOrderIdExternalKeystringNoThe purchase return order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Return shipment numberPackingSlipIdstringYesThe return shipment (product receipt) number
Posting DatePostingDatedateNoShip date. Defaults to system date.
Preview modePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported.

creditPurchaseReturn​

Posts the vendor credit note for a purchase return order. Once the return has shipped, the credit is built from the posted return shipments (as invoicePurchaseOrder invoices what was received); otherwise from the ordered quantity. PostedDocumentId is the credit note number.

Request Contract: MGCLatticePurchaseReturnCreditRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase order IDPurchaseOrderIdstringYesPurchase return order number
Purchase order ID keyPurchaseOrderIdExternalKeystringNoThe purchase return order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Credit note numberInvoiceIdstringYesThe vendor's credit note number
Posting DatePostingDatedateNoCredit date. Defaults to system date.
Preview modePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported.

7. Free Text Invoice Service​

Service: MGCLatticeFreeTextInvoiceService Service Group: MGCLatticeAccountsReceivableServiceGroup

postFreeTextInvoice​

Creates and posts a free text invoice with one or more lines. An empty (null) line, a line with neither AmountCur nor UnitPrice, and a line whose AmountCur is not Quantity x UnitPrice (to 0.01) are refused with ValidationFailed before anything is created. A line MainAccountId that does not resolve in the legal entity's chart of accounts fails the request with DimensionValueNotFound. Success is reported only when the invoice is posted; DocumentId and PostedDocumentId are the posted invoice number.

Request Contract: MGCLatticeFreeTextInvoicePostRequestContract

FieldJSON KeyTypeRequiredDescription
Invoice AccountInvoiceAccountstringYesCustomer account number
Invoice Account keyInvoiceAccountExternalKeystringNoThe customer's alternate key in ExternalSystem, used in place of InvoiceAccount.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Currency CodeCurrencyCodestringNoInvoice currency (defaults from customer)
Posting DatePostingDatedateNoInvoice date. Defaults to system date.
Due DateDueDatedateNoPayment due date
LinesLinesMGCLatticeFreeTextInvoiceLineContract[]YesAt least one invoice line required

Line Contract: MGCLatticeFreeTextInvoiceLineContract

FieldJSON KeyTypeRequiredDescription
DescriptionDescriptionstringNoLine description
Main Account IDMainAccountIdstringNoRevenue main account number
AmountAmountCurdecimalOne of AmountCur / UnitPriceLine amount in the invoice currency. When 0 it is Quantity x UnitPrice; when both are sent it must equal Quantity x UnitPrice
QuantityQuantitydecimalNoQuantity (defaults to 1)
Unit PriceUnitPricedecimalOne of AmountCur / UnitPricePrice per unit. When 0 it is AmountCur / Quantity
Sales Tax GroupSalesTaxGroupstringNoSales tax group code
Item Sales Tax GroupItemSalesTaxGroupstringNoItem sales tax group code
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"InvoiceAccount": "US-001",
"CurrencyCode": "USD",
"PostingDate": "2026-01-15",
"DueDate": "2026-02-15",
"Lines": [
{
"Description": "Consulting services",
"MainAccountId": "110110",
"AmountCur": 5000.00,
"Quantity": 1,
"UnitPrice": 5000.00,
"SalesTaxGroup": "ALL",
"ItemSalesTaxGroup": "ALL"
}
]
}
}

cancelFreeTextInvoice​

Cancels a posted free text invoice by creating and posting a correcting invoice. DocumentId is the canceled invoice; PostedDocumentId is the correcting invoice.

Request Contract: MGCLatticeFreeTextInvoiceCancelRequestContract

FieldJSON KeyTypeRequiredDescription
Invoice RecIdInvoiceRecIdintegerOne of InvoiceRecId / InvoiceIdD365 RecId of the posted CustInvoiceTable record; wins when both are sent
Invoice IDInvoiceIdstringOne of InvoiceRecId / InvoiceIdThe posted free text invoice number, resolved to the record when InvoiceRecId is not sent
Invoice RecId keyInvoiceRecIdExternalKeystringNoThe free text invoice's alternate key in ExternalSystem, used in place of InvoiceRecId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Cancel DateCancelDatedateNoDate for the correcting invoice. Defaults to system date.
Reason CodeReasonCodestringYesFinancial reason code (ReasonTable, customer-enabled - USMF: ERROR, OTHER, ...). F&O will not save a correction without one.
Reason CommentReasonCommentstringNoCancellation reason description
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"InvoiceRecId": 5637144576,
"CancelDate": "2026-01-15",
"ReasonCode": "ERROR",
"ReasonComment": "Invoice entered in error"
}
}

8. General Ledger Journal Service​

Service: MGCLatticeGeneralLedgerJournalService Service Group: MGCLatticeGeneralLedgerServiceGroup

postGeneralJournal / postIntercompanyJournal​

Both operations use the same contract. They create a general journal (a journal name of type Daily, the type the general journal page and the accounts receivable Invoice journal page use), add the lines and post it. A line names its accounts one of two ways: MainAccountId / OffsetMainAccountId (main accounts), or AccountType + AccountNum and OffsetAccountType + OffsetAccountNum, where the type is sent as an integer: 0 Ledger (a main account), 1 Customer, 2 Vendor, 6 Bank. A line that sends both styles is refused with ValidationFailed. A journal whose lines are all main accounts posts all lines in one voucher.

When a line has a customer, vendor or bank account, the lines are filled the way the journal page fills them: a customer line takes the customer's currency, terms of payment, method of payment and sales tax group, the posting profile of the accounts receivable parameters, and a due date calculated from the terms of payment when the line has an invoice number; a vendor line takes the vendor's values the same way; a bank line takes the bank account's currency. Values the line sends (invoice number, document number and date, terms of payment, due date, posting profile, sales tax groups, method of payment, payment reference, bank transaction type) win over these defaults. Sales tax is calculated when the journal posts, as on the journal page (for example a customer invoice line with the customer's sales tax group and the default item sales tax group: the customer owes the amount plus the tax). The offset account is always the one the line sends; a line without one balances against the other lines of its voucher. A line with a customer, vendor or bank account and an offset account is a voucher of its own; all other lines share one voucher.

Unless the general ledger parameter Allow multiple transactions within one voucher is set, a voucher may hold only one customer or vendor transaction and only one bank transaction, as the standard posting requires: a request that would break this is refused with BusinessRule before anything is created (a journal name that allocates vouchers at posting is not checked: the posting groups those lines itself). A transfer between two bank accounts is therefore sent as two bank lines, each against an interim main account. A customer line posts a customer invoice that a payment can settle (settleCustomerTransactions).

Success is reported only when the journal is posted; DocumentId and PostedDocumentId are the journal number. The journal carries the request's Description. The lines carry transaction type General journal, as the general journal page sets them, so a posted journal, customer and vendor vouchers included, can be reversed with reverseJournal or the standard Reverse. Both operations support PreviewMode (validation only, including the accounts and setup records the lines name: nothing is created or posted).

postIntercompanyJournal also takes OffsetCompany on a line: the offset account (main account, customer, vendor or bank account) is in that legal entity, and the intercompany accounting of the two legal entities must be set up. postGeneralJournal refuses OffsetCompany (an offset in another legal entity needs postIntercompanyJournal).

Request Contract: MGCLatticeGeneralJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesLedger journal name (must be Daily type)
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoDefault transaction date. Defaults to system date.
External SystemExternalSystemstringWhen a line sends an external keyThe external system of the lines' AccountNumExternalKey / OffsetAccountNumExternalKey (an id from System administration > Setup > Lattice > External systems). See Cross-reference keys.
LinesLinesMGCLatticeGeneralJournalLineContract[]YesAt least one journal line required

Line Contract: MGCLatticeGeneralJournalLineContract

FieldJSON KeyTypeRequiredDescription
Main Account IDMainAccountIdstringYes, unless the line uses AccountType / AccountNumMain account number for the debit/credit entry
Offset Main Account IDOffsetMainAccountIdstringNoOffset account number
Account TypeAccountTypeintegerNoType of AccountNum: 0 Ledger (default), 1 Customer, 2 Vendor, 6 Bank. Not with MainAccountId
AccountAccountNumstringWith AccountTypeMain account, customer account, vendor account or bank account id
Account External KeyAccountNumExternalKeystringNoThe customer's or vendor's alternate key in ExternalSystem, in place of AccountNum. Not for main accounts or bank accounts
Offset Account TypeOffsetAccountTypeintegerNoType of OffsetAccountNum, same values. Not with OffsetMainAccountId
Offset AccountOffsetAccountNumstringWith an offset type other than 0The offset account; none = the line balances against the other lines of its voucher
Offset Account External KeyOffsetAccountNumExternalKeystringNoThe offset customer's or vendor's alternate key in ExternalSystem (resolved in the offset company of an intercompany line)
Debit AmountAmountCurDebitdecimalNoDebit amount in transaction currency
Credit AmountAmountCurCreditdecimalNoCredit amount in transaction currency
Currency CodeCurrencyCodestringOn a line whose account is a main accountTransaction currency. A customer, vendor or bank line takes the account's currency
DescriptionDescriptionstringNoLine description/voucher text
Transaction DateTransDatedateNoLine-level transaction date (overrides header)
Offset CompanyOffsetCompanystringNopostIntercompanyJournal only: the legal entity the offset posts in. Refused by postGeneralJournal
InvoiceInvoiceIdstringNoThe line's invoice number (a customer or vendor line posts the invoice under it; the due date is calculated from the terms of payment only when it is sent)
Document NumberDocumentNumberstringNoDocument number
Document DateDocumentDatedateNoDocument date (a vendor invoice line's due date is calculated from it)
Due DateDueDatedateNoCustomer or vendor line only. Default: calculated from the terms of payment
Terms of PaymentPaymentTermsIdstringNoCustomer or vendor line only. Default: the account's terms of payment
Posting ProfilePostingProfilestringNoCustomer or vendor line only. Default: the accounts receivable / payable parameters' posting profile
Sales Tax GroupSalesTaxGroupstringNoDefault: the customer's or vendor's sales tax group, or the main account's
Item Sales Tax GroupItemSalesTaxGroupstringNoDefault: the ledger account's or the default item sales tax group (on a customer or vendor line only with an invoice number)
Method of PaymentMethodOfPaymentstringNoCustomer or vendor line only. Default: the account's method of payment
Payment ReferencePaymentReferencestringNoPayment reference
Bank Transaction TypeBankTransactionTypestringNoLine with a bank account only
DimensionsDimensionsMGCLatticeDimensionValueContract[]NoFinancial dimension values of the line's account (see section 22): merged into the main account of a ledger line, into the default dimensions of a customer, vendor or bank line

Error codes:

ErrorCodeWhen
ValidationFailed (1)An empty line; a line that sends both account styles; an AccountType / OffsetAccountType other than 0, 1, 2, 6; a typed line without AccountNum (or its key); an offset type other than Ledger without OffsetAccountNum; a main-account line without CurrencyCode; OffsetCompany on postGeneralJournal; PaymentTermsId, DueDate, PostingProfile or MethodOfPayment on a line without a customer or vendor account; BankTransactionType on a line without a bank account; an external key on a main account or bank account; an unknown customer, vendor or bank account (an offset account in the offset company); unknown terms of payment, posting profile, method of payment, sales tax group, item sales tax group or bank transaction type; an external key that does not resolve, or a key without ExternalSystem
BusinessRule (4)A voucher would hold two customer or vendor transactions, or two bank transactions (for example one line from one bank account to another), while Allow multiple transactions within one voucher is off; the standard posting refuses the journal (the journal is deleted again; the standard messages are in Errors)
DimensionValueNotFound (5)A main account, offset main account or dimension value that does not resolve
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "GenJrn",
"Description": "Monthly accrual entries",
"PostingDate": "2026-01-31",
"Lines": [
{
"MainAccountId": "600100",
"AmountCurDebit": 10000.00,
"CurrencyCode": "USD",
"Description": "Accrued expenses"
},
{
"MainAccountId": "200100",
"AmountCurCredit": 10000.00,
"CurrencyCode": "USD",
"Description": "Accrued expenses - offset"
}
]
}
}

A customer invoice, defaulted from the customer:

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "9b2e6a51-3c1d-4f8e-a0b7-5d6c7e8f9a01",
"LegalEntityId": "USMF",
"JournalNameId": "GenJrn",
"Description": "Customer invoices",
"Lines": [
{
"AccountType": 1,
"AccountNum": "US-001",
"OffsetAccountType": 0,
"OffsetAccountNum": "401100",
"InvoiceId": "INV-10045",
"AmountCurDebit": 1250.00,
"Description": "Consulting, March"
}
]
}
}

A transfer between two bank accounts, as two bank lines against an interim main account (use your interim or bank transfer clearing account in place of 110180):

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "1d4c8b2a-7e6f-4a3b-9c0d-2e1f3a4b5c6d",
"LegalEntityId": "USMF",
"JournalNameId": "GenJrn",
"Description": "Bank transfer",
"Lines": [
{
"AccountType": 6,
"AccountNum": "USMF OPER",
"OffsetAccountType": 0,
"OffsetAccountNum": "110180",
"AmountCurCredit": 5000.00,
"BankTransactionType": "05",
"Description": "Fund payroll account - out"
},
{
"AccountType": 6,
"AccountNum": "USMF PAYRL",
"OffsetAccountType": 0,
"OffsetAccountNum": "110180",
"AmountCurDebit": 5000.00,
"BankTransactionType": "05",
"Description": "Fund payroll account - in"
}
]
}
}

reverseJournal​

Reverses a posted ledger journal, every voucher or the one Voucher names, the way the posted journal's Reverse does. Each voucher is reversed by the standard engine the transaction reversal chooses for it:

VoucherStandard reversal
General ledger transactions only, posted with transaction type General journal, Allocation or EliminationTransaction reversal (TransactionReversal_Ledger)
A customer transaction not posted to a bank accountCustomer transaction reversal (TransactionReversal_Cust)
A vendor transaction not posted to a bank accountVendor transaction reversal (TransactionReversal_Vend)
A customer payment posted to a bank accountPayment cancellation (BankPaymCancel), which also reverses its settlements
Any other bank voucher, fixed asset or project transactionsNot reversed: refused with BusinessRule (they are reversed in their own module; a fixed asset voucher with reverseAssetTransaction)

Every voucher is checked before anything is reversed, and all vouchers are reversed in one transaction: either all are reversed or, when one fails, none is. The operation has no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. It is idempotent on RequestId, and it can also be queued with submitAsyncOperation (see 21. Async Operations).

Request Contract: MGCLatticeJournalReversalRequestContract

FieldJSON KeyTypeRequiredDescription
Journal NumberJournalNumstringOne of JournalNum / JournalNumExternalKey / VoucherThe posted journal
Journal Number keyJournalNumExternalKeystringNoThe journal's alternate key in ExternalSystem, used in place of JournalNum.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member. See Cross-reference keys.
VoucherVoucherstringNoOne voucher of the journal to reverse. Sent alone, it names the journal that contains it
Reversal DateReversalDatedateNoDate of the reversal. Defaults to system date; not before a voucher's date
Reason CodeReasonCodestringWhen the parameters demand oneFinancial reason code (ReasonTable). Required for customer vouchers when the accounts receivable parameters require a reason for transaction reversal, and for customer bank payments when they require one for payment cancellation
Reason CommentReasonCommentstringNoReason text
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNum": "00045",
"ReversalDate": "2026-02-01",
"ReasonCode": "ERROR",
"ReasonComment": "Accrual posted twice"
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the reversed journal; PostedDocumentId is the reversal voucher of the journal's first voucher. The message lists every voucher with its reversal voucher (Journal 00045 reversed: 1 voucher(s), original > reversal: GNJL001234 > GNJL001240.); the standard engines' messages are in InformationalMessages.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No RequestId, LegalEntityId, journal or voucher; an unknown reason code; a reversal date before a voucher's date; a voucher found in several journals (send JournalNum); a reason the parameters require is missing
DocumentNotFound (2)An unknown journal; a voucher in no journal, or not in the named journal
InvalidStatus (3)The journal is not posted; a voucher is already reversed (or its reversal revoked), or a customer payment is already canceled
BusinessRule (4)A voucher not in the general ledger; a voucher no standard reversal covers (Voucher X of journal Y cannot be reversed by the standard journal reversal. It reverses general journal, allocation and elimination vouchers, customer and vendor transactions, and customer payments posted to a bank account; bank, fixed asset and project transactions are reversed in their own module.); a voucher with several customer payments posted to a bank account (reverse each with reverseCustomerPayment); a general ledger transaction the standard reversal cannot reverse (posting type, journalized entry, closed year, intercompany account); a settled customer or vendor transaction (unsettle it first); a posted journal without vouchers; or a refusal of the standard engine, with its message in Errors
ConfigurationMissing (11)The general ledger number sequences for the reversal voucher and the trace number (or, for a payment cancellation, the customer closing voucher) are not set up
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: reverseJournalBatch takes a _requests list of MGCLatticeJournalReversalRequestContract and returns MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations). The batch operation is not registered for async execution.

Security: high-risk. reverseJournal and its batch are granted only by MGCLatticeGeneralLedgerJournalReverseMaintain (General ledger - reverse posted journals (high-risk)), which is in MGCLatticeIntegrationServiceHighRiskDuty; MGCLatticeGeneralLedgerServiceMaintain does not grant them.


8a. Journal Posting Service​

Service: MGCLatticeJournalPostingService Service Group: MGCLatticeJournalPostingServiceGroup Security: MGCLatticeJournalPostingMaintain (Journal posting - post existing journals) grants Invoke on the five operations and their batch twins. It is in MGCLatticeIntegrationServiceOperationsDuty. The privilege alone posts nothing: each journal is also checked against the caller's rights to the Lattice operations that would post its content (see Who may post what below).

Posts a journal that already exists in the legal entity - entered on its journal page, imported through data management, or created through the standard journal entities (for example LedgerJournalHeaders + LedgerJournalLines) - with the standard posting the journal page's Post runs. The journal posts completely or not at all: on a refusal it stays as it was. Use it when another system or person prepares the journal and the integration only decides when it posts.

OperationJournalsStandard posting
postLedgerJournalGeneral journal, customer payment journal, vendor payment journal, invoice register, vendor invoice journal, invoice approval journal, project expense journal, fixed asset journalThe journal page's Post (not Post and transfer): one voucher that fails cancels the whole posting
postInventoryJournalMovement, profit/loss (adjustment), counting, transfer, BOM, tag counting, ownership change, project item and fixed asset inventory journalsThe inventory journal posting of the journal type
postProjectJournalProject hour and fee journalsThe project journal posting
postProductionJournalPicking list, route card, job card and report as finished journalsThe production journal posting of the journal type
postTradeAgreementJournalTrade agreement journals (sales and purchase prices and discounts)The trade agreement journal posting (validate all lines, then post)

None of the operations has a preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. They are idempotent on RequestId.

Request Contract: MGCLatticeLedgerJournalPostingRequestContract (postLedgerJournal)

FieldJSON KeyTypeRequiredDescription
Journal NumberJournalNumstringOne of JournalNum / JournalNumExternalKeyThe ledger journal (journal batch number)
Journal Number keyJournalNumExternalKeystringNoThe journal's alternate key in ExternalSystem, used in place of JournalNum.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with JournalNumExternalKey. See Cross-reference keys.
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Request Contract: MGCLatticeJournalPostingRequestContract (postInventoryJournal, postProjectJournal, postProductionJournal)

FieldJSON KeyTypeRequiredDescription
Journal IDJournalIdstringYesThe journal number of the inventory, project or production journal
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Request Contract: MGCLatticeTradeAgreementJournalPostingRequestContract (postTradeAgreementJournal)

FieldJSON KeyTypeRequiredDescription
Journal NumberJournalNumstringYesThe trade agreement journal number
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNum": "00512"
}
}

The other operations take the same body with their own journal member, for example "JournalId": "00087" for postInventoryJournal.

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the journal. PostedDocumentId is, for a ledger journal, its first voucher in voucher order (the message counts the vouchers and lists the first 25: Ledger journal 00512 (Daily) was posted with 2 vouchers: GNJL001301, GNJL001302.); for every other journal, the journal again. For a tag counting journal the message names the counting journal the posting created, which stays open for review as the standard leaves it. Warnings and information from the posting are in Warnings and InformationalMessages.

Who may post what. Besides MGCLatticeJournalPostingMaintain, the caller must hold every Lattice operation that would post the journal's content: the operation of the journal's type and, for a ledger journal, the operations its lines need. Posting an existing journal therefore never lets a caller do more than the operations it holds would. When any is missing, the request is refused with AccessDenied, and the message names all the missing operations.

Journal typeOperation the caller must hold
General journalMGCLatticeGeneralLedgerJournalService.postGeneralJournal
Customer payment journalMGCLatticePaymentJournalService.postCustomerPaymentJournal
Vendor payment journalMGCLatticePaymentJournalService.postVendorPaymentJournal
Invoice register, vendor invoice journalMGCLatticeVendorInvoiceJournalService.postInvoiceRegisterJournal
Invoice approval journalMGCLatticeVendorInvoiceJournalService.postInvoiceApprovalJournal
Project expense journal (ledger, type Cost)MGCLatticeProjectJournalService.postExpenseJournal
Fixed asset journalDecided by its lines (see the next table)
Fixed asset inventory journal (inventory, type Fixed asset)MGCLatticeFixedAssetService.postAcquisition
Inventory movement / profit-loss / counting / transfer / BOM / tag counting / ownership change journalMGCLatticeInventoryJournalPostingService.postMovementJournal / postAdjustmentJournal / postCountingJournal / postTransferJournal / postBOMJournal / postTagCountingJournal / postOwnershipChangeJournal
Project item journal (inventory, type Project)MGCLatticeProjectJournalService.postItemJournal
Project hour / fee journalMGCLatticeProjectJournalService.postHourJournal / postFeeJournal
Picking list / route card and job card / report as finished journalMGCLatticeProductionOrderPostingService.postPickList / postRouteCard / reportAsFinished
Trade agreement journalMGCLatticeSalesTradeAgreementService.setSalesPrice

In addition, by line, in a ledger journal of any type:

LineOperation the caller must also hold
Intercompany line: its account company or offset company is another legal entity (as the standard posting decides it)MGCLatticeGeneralLedgerJournalService.postIntercompanyJournal
Fixed asset line (every line of a fixed asset journal; in any other journal, a line whose account or offset type is Fixed assets) with transaction type AcquisitionMGCLatticeFixedAssetService.postAcquisition
Fixed asset line with transaction type Disposal - sale or Disposal - scrapMGCLatticeFixedAssetService.postDisposal
Fixed asset line with any other transaction type (acquisition adjustment, depreciation, revaluation, write-up or write-down adjustment, ...)MGCLatticeFixedAssetService.postAssetTransaction
Project line (account or offset type Project)MGCLatticeProjectJournalService.postExpenseJournal

Customer, vendor and bank lines of a general journal are covered by postGeneralJournal. Example: a general journal with an intercompany line and a fixed asset disposal line needs postGeneralJournal, postIntercompanyJournal and postDisposal. Journals of any other type (allocation, elimination, periodic, budget, project beginning balance, ...) are refused with ValidationFailed.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No RequestId or LegalEntityId, an unknown legal entity; no journal named, or a journal key that does not resolve; a journal type no Lattice operation posts (the message lists the types the operation posts); a journal without lines
DocumentNotFound (2)No such journal in the legal entity
AccessDenied (14)The caller does not hold every operation the journal needs - the one of its type and, for a ledger journal, those of its intercompany, fixed asset and project lines (the message names all the missing ones)
InvalidStatus (3)The journal is already posted (for a trade agreement journal, the only state checked before the standard posting); it is locked by the system (being validated or posted), locked by another user, private to another user, locked by a user group the caller is not in, or in use by another user; a ledger or inventory journal is in a workflow approval that has not approved it (the message names the approval status), or a ledger journal's journal name requires approval and the journal has not been approved; a project journal under journal approval has a status that is not ready for posting (this applies to every caller, system administrators included)
BusinessRule (4)The standard posting refuses the journal (accounts, dimensions, closed period, on-hand, item on hold, production order status, overlapping trade agreement ranges when the accounts receivable parameters check for them, ...); the standard messages are in Errors and Warnings. Also a ledger journal above the ledger journal line limit posted outside batch: the standard posts it only in batch, so post it through the async operations
TransientRuntime (6)A runtime fault; IsRetryable true

Report as finished journals. As on the page, the quality orders that quality associations require before a report as finished are created before the posting and stay when the posting is then refused.

Trade agreement journals. A journal of trade agreements marked for deletion (the journal page's Delete trade agreements) posts as the page posts it: the posting deletes those agreements.

Async. All five operations can be queued with submitAsyncOperation (see 21. Async Operations): posting a large journal can outlast a synchronous call. Submitting needs the same rights as a direct call.

Batch: postLedgerJournalBatch, postInventoryJournalBatch, postProjectJournalBatch, postProductionJournalBatch and postTradeAgreementJournalBatch take a _requests list of their operation's request contract and return MGCLatticeBulkOperationResponseContract with one result per journal (see 19. Bulk Operations). The batch operations are not registered for async execution.


9. Payment Journal Service​

Service: MGCLatticePaymentJournalService Service Group: MGCLatticeGeneralLedgerServiceGroup

postCustomerPaymentJournal / postVendorPaymentJournal​

Creates and posts a payment journal. The service validates the journal name matches the expected type: Customer payment (CustPayment, USMF CustPay) or Vendor disbursement (Payment, USMF VendPay). An empty (null) line, a line AccountNum that is not an existing customer (customer payment) or vendor (vendor payment), a BankAccountId that is not an existing bank account, and an InvoiceId on a vendor payment line are refused with ValidationFailed before the journal is created. Every payment line is approved by the calling user when it is created, as the payment journal page does (the standard reversal refuses a transaction that is not approved). Success is reported only when the journal is posted; DocumentId and PostedDocumentId are the journal number. The journal carries the request's Description.

Prepayments. A line with IsPrepayment: true is a prepayment (the payment journal's Prepayment journal voucher):

  • It posts with the prepayment posting profile of the accounts receivable or accounts payable parameters ("Posting profile with prepayment journal voucher"; USMF: PRE). Without one the standard posts with the default posting profile, and the response says so in Warnings.
  • When the parameters calculate sales tax on prepayments ("Sales tax on prepayment journal voucher"), the journal is created with Amounts include sales tax (posting requires it), and the line takes the customer's or vendor's sales tax group and the default item sales tax group of the sales tax parameters, as the payment journal does; the tax is calculated when the journal posts.

A line with SalesOrderId (customer payments) or PurchaseOrderId (vendor payments) is marked against that order. The order is checked before the journal is created: it must exist, be invoiced to the line's account, and be neither invoiced nor canceled. After posting, the payment is marked against the order exactly as the order's Settle transactions does (settlement type Marked transactions), so the order's invoice settles it. InformationalMessages names the order; a payment that could not be marked is reported in Warnings (the payment is posted). An order can be named on any payment line, prepayment or not. Order checks that fail are refused before anything is created:

ErrorCodeWhen
ValidationFailed (1)A SalesOrderId on a vendor payment line, a PurchaseOrderId on a customer payment line, an unknown order, or an order invoiced to another account than the line's
InvalidStatus (3)The order is already invoiced or canceled

Customer prepayments are recorded this way; there is no sales prepayment invoice operation. A vendor prepayment invoice for a purchase order is posted with postPurchasePrepaymentInvoice.

Check payments (GeneratePayments). A vendor payment line whose method of payment needs Generate payments before it can post (payment type Check, a check number demanded by the method's payment control, or payment status Sent demanded; USMF CHECK) is refused at posting with the standard "Check number must be filled in" (BusinessRule), and the journal is deleted. With GeneratePayments: true on postVendorPaymentJournal, those lines get their checks first, drawn on the line's BankAccountId with the next numbers of its check layout, exactly as generateVendorPayments draws them; the generation and the posting are one transaction, so a posting that fails uses no check. The message lists the check numbers; DocumentId and PostedDocumentId stay the journal. Lines whose method posts without generation are posted as they are. Refused before anything is created:

ErrorCodeWhen
ValidationFailed (1)GeneratePayments on postCustomerPaymentJournal; a line that needs generation without BankAccountId; a line whose method of payment exports a payment file or uses an Electronic reporting format
ConfigurationMissing (11)A method of payment without export format; a bank account without check layout, or with fixed check numbering and no created checks left

Request Contract: MGCLatticePaymentJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesPayment journal name
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoDefault transaction date
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Generate PaymentsGeneratePaymentsbooleanNopostVendorPaymentJournal only: true generates the checks of the lines that need them before the journal posts (see Check payments above). Default false. Refused by postCustomerPaymentJournal
LinesLinesMGCLatticePaymentJournalLineContract[]YesAt least one payment line required

Line Contract: MGCLatticePaymentJournalLineContract

FieldJSON KeyTypeRequiredDescription
Account NumberAccountNumstringYesCustomer or vendor account number
Account Number keyAccountNumExternalKeystringNoThe customer's (customer payment journal) or vendor's (vendor payment journal) alternate key in ExternalSystem, used in place of AccountNum.
Debit AmountAmountCurDebitdecimalNoDebit amount
Credit AmountAmountCurCreditdecimalNoCredit amount
Currency CodeCurrencyCodestringNoTransaction currency. Defaults to the customer's or vendor's currency
Bank Account IDBankAccountIdstringNoThe bank account the payment is made from or received into (the line's offset account, type Bank). Empty uses the journal name's offset account
Method of PaymentMethodOfPaymentstringNoPayment method code
Invoice IDInvoiceIdstringNoCustomer payments only: the invoice the payment pays, stored on the line so settleCustomerTransactions can find the payment by that invoice number (PaymentInvoiceId). Refused on vendor payment lines
DescriptionDescriptionstringNoPayment description
Transaction DateTransDatedateNoLine-level date
PrepaymentIsPrepaymentbooleanNotrue makes the line a prepayment (see Prepayments above). Default false
Sales Order IDSalesOrderIdstringNoCustomer payments only: the sales order the payment is marked against. Refused on vendor payment lines
Sales Order ID keySalesOrderIdExternalKeystringNoThe sales order's alternate key in ExternalSystem, used in place of SalesOrderId.
Purchase Order IDPurchaseOrderIdstringNoVendor payments only: the purchase order the payment is marked against. Refused on customer payment lines
Purchase Order ID keyPurchaseOrderIdExternalKeystringNoThe purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "CustPay",
"Description": "Customer payment batch",
"PostingDate": "2026-01-15",
"Lines": [
{
"AccountNum": "US-001",
"AmountCurCredit": 5000.00,
"CurrencyCode": "USD",
"BankAccountId": "USMF OPER",
"MethodOfPayment": "CHECK",
"InvoiceId": "INV-001",
"Description": "Payment for INV-001"
}
]
}
}

A customer deposit (prepayment) marked against a sales order:

{
"_request": {
"RequestId": "5d0e8f2a-3c41-4b7e-9a62-1f8d4c3b2a90",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "CustPay",
"Description": "Customer deposit",
"Lines": [
{
"AccountNum": "US-001",
"AmountCurCredit": 500.00,
"CurrencyCode": "USD",
"BankAccountId": "USMF OPER",
"IsPrepayment": true,
"SalesOrderId": "SO-000123",
"Description": "Deposit for SO-000123"
}
]
}
}

settleCustomerTransactions / settleVendorTransactions​

Settles a payment transaction against one or more invoice transactions, marking their open balances as the Settle open transactions page does. The payment must be a payment transaction of AccountNum, and each line must name a transaction of AccountNum that is not a payment; a RecId that names another account's transaction, or a payment as an invoice, fails the request with DocumentNotFound. A payment or invoice with no open balance, or a request that settles nothing, fails the request. On success DocumentId is the voucher of the settled payment; a settlement produces no document of its own, so PostedDocumentId is empty.

Request Contract: MGCLatticeSettlementRequestContract

FieldJSON KeyTypeRequiredDescription
Account NumberAccountNumstringYesCustomer or vendor account number
Account Number keyAccountNumExternalKeystringNoThe customer's (customer settlement) or vendor's (vendor settlement) alternate key in ExternalSystem, used in place of AccountNum.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Payment Trans RecIdPaymentTransRecIdintegerOne of the threeRecId of the payment transaction (CustTrans/VendTrans) of AccountNum
Payment VoucherPaymentVoucherstringOne of the threeUsed when PaymentTransRecId is not sent: the voucher of the posted payment. The way to identify a vendor payment
Payment Invoice IDPaymentInvoiceIdstringOne of the threeUsed when neither PaymentTransRecId nor PaymentVoucher is sent: the invoice number the payment carries (a customer payment posted with a line InvoiceId)
LinesLinesMGCLatticeSettlementLineContract[]YesAt least one settlement line required

Line Contract: MGCLatticeSettlementLineContract

FieldJSON KeyTypeRequiredDescription
Invoice Trans RecIdInvoiceTransRecIdintegerOne of the twoRecId of the transaction of AccountNum to settle against (not a payment)
Invoice IDInvoiceIdstringOne of the twoUsed when InvoiceTransRecId is not sent: the invoice number of a transaction of AccountNum
Settle AmountSettleAmountCurdecimalNoAmount to settle in transaction currency; 0 or omitted settles the whole open balance
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"AccountNum": "US-001",
"PaymentTransRecId": 5637144577,
"Lines": [
{
"InvoiceTransRecId": 5637144575,
"SettleAmountCur": 5000.00
}
]
}
}

reverseCustomerPayment / reverseVendorPayment​

Reverses a posted payment voucher of a customer (reverseCustomerPayment) or vendor (reverseVendorPayment) account with the standard reversal that covers it:

PaymentCustomerVendor
Made by check (a check of the payment's bank account with the voucher and the payment reference as its number)Check reversal (BankChequeCancel, the Checks page's Payment reversal), through a check reversal journal when the parameters require review (see below)The same
Posted to a bank account, not by checkPayment cancellation (BankPaymCancel): it reverses the payment's settlements, so the invoices it paid are open againRefused with BusinessRule: the standard reverses a vendor payment to a bank account only as a check reversal
Not posted to a bank accountTransaction reversal (TransactionReversal_Cust); a settled payment is refused (unsettle it first)Transaction reversal (TransactionReversal_Vend); a settled payment is refused

When the cash and bank management parameters require check reversals to be reviewed in a check reversal journal (Use review process for payment reversals; USMF has it on), the check reversal does what the Checks page's Payment reversal does then: it creates a check reversal journal with the canceling line, and the check becomes Pending cancellation. The journal is left for review (PostedDocumentId is the journal), or, with PostReversalJournal, posted in the same request, which reverses the payment and its settlements and cancels the check (PostedDocumentId is the reversal voucher). The reversal runs in one transaction. The operations have no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. They are idempotent on RequestId.

Request Contract: MGCLatticePaymentReversalRequestContract

FieldJSON KeyTypeRequiredDescription
Account NumberAccountNumstringYesThe customer (reverseCustomerPayment) or vendor (reverseVendorPayment) account
Account Number keyAccountNumExternalKeystringNoThe customer's or vendor's alternate key in ExternalSystem, used in place of AccountNum.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member. See Cross-reference keys.
VoucherVoucherstringYesThe payment voucher (a transaction of type Payment of the account)
Reversal DateReversalDatedateNoDate of the reversal. Defaults to system date; not before the payment date
Reason CodeReasonCodestringWhen the parameters demand oneFinancial reason code (ReasonTable). Required when the accounts receivable parameters require a reason for transaction reversal or payment cancellation, or the cash and bank management parameters require one for payment reversal (checks)
Reason CommentReasonCommentstringNoReason text
Reversal Journal Name IDReversalJournalNameIdstringNoCheck reversals under review only: a journal name of type Check reversal (USMF CheckRev) for the check reversal journal. Without it, the legal entity's only check reversal journal name
Post Reversal JournalPostReversalJournalbooleanNoCheck reversals under review only: true posts the check reversal journal in the same request. Default false (the journal is left for review)
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"AccountNum": "US-001",
"Voucher": "ARP-000123",
"ReasonCode": "ERROR",
"ReasonComment": "Payment applied to the wrong customer"
}
}

A vendor check payment, reversed through a posted check reversal journal:

{
"_request": {
"RequestId": "2b7d9c41-6e3a-4f05-8d12-9a0c4e5f6b73",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"AccountNum": "US-101",
"Voucher": "APPM-000210",
"ReversalJournalNameId": "CheckRev",
"PostReversalJournal": true
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the reversed payment voucher; PostedDocumentId is the voucher of the cancellation or reversal (Customer payment ARP-000123 of account US-001 reversed with voucher ARP-000130.), or the check reversal journal when it is left for review.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No RequestId, LegalEntityId, account or voucher; an unknown customer, vendor or reason code; a reversal date before the payment date; a reason the parameters require is missing; a ReversalJournalNameId that does not exist or is not a check reversal journal name; several check reversal journal names and none requested
DocumentNotFound (2)No payment with that voucher on the account
InvalidStatus (3)The payment is already canceled or reversed; its check is already reversed or pending reversal (a check reversal journal exists for it), or is not in status Payment
BusinessRule (4)A vendor payment posted to a bank account other than by check; a customer bank payment that cannot be canceled (post-dated check, letter of credit); a settled payment not posted to a bank account; or a refusal of the standard engine, with its message in Errors
ConfigurationMissing (11)The number sequence the reversal draws from (general ledger reversal voucher and trace number, or the customer or vendor closing voucher) is not set up; for a check reversal under review, no check reversal journal name, a journal name without a voucher series, or the general ledger parameters' journal number sequence not set up
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: reverseCustomerPaymentBatch and reverseVendorPaymentBatch take a _requests list of MGCLatticePaymentReversalRequestContract and return MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations).

Security: high-risk. The two operations and their batches are granted only by MGCLatticePaymentReverseMaintain (Payments - reverse customer and vendor payments (high-risk)), which is in MGCLatticeIntegrationServiceHighRiskDuty; MGCLatticeGeneralLedgerServiceMaintain does not grant them.


10. Workflow Action Service​

Service: MGCLatticeWorkflowActionService Service Group: MGCLatticeWorkflowServiceGroup

submitToWorkflow​

Submits a document to a D365 workflow the way the document's own Submit does. Supported document table: PurchReqTable (purchase requisitions, workflow type PurchReqReview); any other table is refused with ValidationFailed, because submitting it would start a workflow without the document's own submit logic. Before anything is submitted the requisition must exist (DocumentNotFound), be a draft and have no workflow in progress (InvalidStatus), have lines, be submitted by its preparer - the calling user must be mapped to the requisition's preparer worker - and pass the standard submission rules (BusinessRule; the reasons are in Errors), and a workflow configuration of the type must apply to it (ConfigurationMissing). The requisition then moves to In review and the workflow is activated in one transaction, with the preparer as the submitting user. On success DocumentId is the correlation id of the workflow instance (lower case, without braces) - the key the work-item actions, recallWorkflow and getWorkflowStatus take. The work items themselves are created asynchronously by the Workflow message processing batch job, usually within a minute.

Request Contract: MGCLatticeWorkflowSubmitRequestContract

FieldJSON KeyTypeRequiredDescription
Workflow Type NameWorkflowTypeNamestringYesD365 workflow type name (e.g., PurchReqReview)
Record RecIdRecordRecIdintegerOne of RecordRecId / DocumentNumberRecId of the record to submit; wins when both are sent
Document NumberDocumentNumberstringOne of RecordRecId / DocumentNumberThe document's number (a purchase requisition number for PurchReqTable), resolved to the record when RecordRecId is not sent
Table NameTableNamestringYesTable name of the record: PurchReqTable
CommentCommentstringNoSubmission comment. Defaults to auto-generated message.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"WorkflowTypeName": "PurchReqReview",
"RecordRecId": 5637144576,
"TableName": "PurchReqTable",
"Comment": "Submitted for approval via integration"
}
}

approveWorkItem / rejectWorkItem / delegateWorkItem​

Takes an action on a pending workflow work item as the user named in ActingUserId, who must be the work item's assignee. UserContext is informational here as everywhere else: it never selects the user an action is taken as.

  • approve and reject complete the work item with the outcome of its workflow element (Approve / Reject on an approval step, Complete on a task) through the platform's external work-item completion: the outcome is validated, the document's completion checks run, the Prevent external work item completion workflow parameter is honored, and the action runs as the assignee, so the workflow history records the assignee. A rejected document goes back to the workflow's originator.
  • delegate hands the work item to DelegateToUserId (required; an enabled user other than the acting user), as the assignee.

The work item is found by WorkItemRecId, or else as the pending approval work item of the workflow instance WorkflowCorrelationId assigned to ActingUserId. When there is none the failure says why: the workflow is unknown (DocumentNotFound); it is pending but its work items are not created yet - the Workflow message processing batch job creates them shortly after the submit (InvalidStatus, IsRetryable true: try again later); its work items are assigned to other users (BusinessRule, naming them); or it is no longer pending (InvalidStatus). getWorkflowStatus lists the pending work items and their assignees. DocumentId is the work item's RecId.

Request Contract: MGCLatticeWorkflowActionRequestContract

FieldJSON KeyTypeRequiredDescription
Acting UserActingUserIdstringYesThe user the action is taken as: the work item's assignee
Work Item RecIdWorkItemRecIdintegerOne of WorkItemRecId / WorkflowCorrelationIdRecId of the WorkflowWorkItemTable record (must be Pending and assigned to ActingUserId); wins when both are sent
Workflow Correlation IDWorkflowCorrelationIdstring (GUID)One of WorkItemRecId / WorkflowCorrelationIdThe workflow correlation ID submitToWorkflow returned; the pending work item of that workflow assigned to ActingUserId is acted on
CommentCommentstringNoAction comment
Delegate To UserDelegateToUserIdstringdelegate onlyThe user the work item is delegated to; required by delegateWorkItem, not used by approve and reject
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"ActingUserId": "Inga",
"WorkflowCorrelationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Comment": "Approved via integration service"
}
}

recallWorkflow​

Recalls (cancels) a previously submitted workflow instance. DocumentId is the workflow correlation id (lower case, without braces). The platform cancels the instance asynchronously; a purchase requisition returns to Draft when the cancellation is processed.

Only the workflow's originator may recall it, as the document's Recall button allows, or a caller granted the workflow history's Cancel (WorkflowStatusCancel), as that page allows. Anyone else is refused with ErrorCode AccessDenied; an unknown correlation id is DocumentNotFound.

Request Contract: MGCLatticeWorkflowRecallRequestContract

FieldJSON KeyTypeRequiredDescription
Workflow Correlation IDWorkflowCorrelationIdstring (GUID)YesThe workflow correlation ID returned from submitToWorkflow
CommentCommentstringNoRecall reason. Defaults to auto-generated message.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"WorkflowCorrelationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Comment": "Recalled - data correction needed"
}
}

11. Budget Register Service​

Service: MGCLatticeBudgetRegisterService Service Group: MGCLatticeGeneralLedgerServiceGroup

postBudgetEntry / postBudgetTransfer​

Creates a budget register entry with lines and posts it through the standard budget register post, as the Post button on the budget register entry page does: the post updates the budget balances, runs budget control, posts to the general ledger when the budget code requires it, and completes the entry. postBudgetEntry needs a budget transaction code of type Original budget; postBudgetTransfer needs one of type Transfer, and its lines must net to zero.

Every line needs a MainAccountId that resolves to a budget account; an unresolved account fails the request with DimensionValueNotFound before anything is created. A missing budget register number sequence or chart of accounts fails with ConfigurationMissing. Every line needs a non-zero Amount (ValidationFailed). Success is reported only when the entry is Completed after the post: DocumentId and PostedDocumentId are the budget register entry number (BudgetTransactionHeader.TransactionNumber). If the post fails, the draft entry the request created is deleted (its number is released) and the response carries the post's errors, so a failed request leaves nothing behind and a retry creates a new entry.

Request Contract: MGCLatticeBudgetEntryPostRequestContract

FieldJSON KeyTypeRequiredDescription
Budget Transaction CodeBudgetTransactionCodestringYesBudget transaction code name
Budget Model IDBudgetModelIdstringYesBudget model identifier
Posting DatePostingDatedateNoDate of the budget register entry. Defaults to today's date in the calling user's time zone.
LinesLinesMGCLatticeBudgetEntryLineContract[]YesAt least one budget line required

Line Contract: MGCLatticeBudgetEntryLineContract

FieldJSON KeyTypeRequiredDescription
Main Account IDMainAccountIdstringYesMain account for the budget entry
AmountAmountdecimalYesBudget amount in transaction currency; not zero
Currency CodeCurrencyCodestringNoTransaction currency. Defaults to the accounting currency
Transaction DateTransDatedateNoLine date. Defaults to PostingDate
CommentCommentstringNoLine comment
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"BudgetTransactionCode": "Original budget",
"BudgetModelId": "FY2026",
"PostingDate": "2026-01-01",
"Lines": [
{
"MainAccountId": "600100",
"Amount": 50000.00,
"CurrencyCode": "USD",
"TransDate": "2026-01-01",
"Comment": "Q1 operating budget"
},
{
"MainAccountId": "600200",
"Amount": 25000.00,
"CurrencyCode": "USD",
"TransDate": "2026-01-01",
"Comment": "Q1 marketing budget"
}
]
}
}

12. Project Journal Service​

Service: MGCLatticeProjectJournalService Service Group: MGCLatticeProjectServiceGroup

postHourJournal / postExpenseJournal / postItemJournal / postFeeJournal​

All four operations use the same contract, but not the same journal table: hour and fee journals are project journals (ProjJournalName of type Hour / Revenue), an expense journal is a ledger journal of type Cost (USMF PrjJrn) and an item journal is an inventory journal of type Project (USMF ProjItem) - ProjJournalType has no expense or item member. Each operation validates the journal name's type and the line categories' type (Hour / Cost / Item / Revenue) before creating anything.

Hour and fee lines are created through the standard journal framework, as the journal form enters them: each line takes its voucher from the journal name's number sequence and its project date from the transaction date, and an hour line's WorkerPersonnelNumber becomes the line's resource. On success DocumentId and PostedDocumentId are the posted journal's number. Every operation fails, rather than answering success, when posting returns without the journal marked posted. If the operation fails after creating the journal, the unposted journal (project, ledger or inventory journal) is deleted, so a failed request leaves no journal behind and a retry with the same RequestId creates it again.

Request Contract: MGCLatticeProjectJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Project IDProjIdstringNoDefault project ID for all lines
Project ID keyProjIdExternalKeystringNoThe default project's alternate key in ExternalSystem, used in place of ProjId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Journal Name IDJournalNameIdstringYesJournal name of the operation's journal kind (see above)
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoDefault transaction date
LinesLinesMGCLatticeProjectJournalLineContract[]YesAt least one line required

Line Contract: MGCLatticeProjectJournalLineContract

FieldJSON KeyTypeRequiredDescription
Project IDProjIdstringNoLine-level project ID (overrides header)
Project ID keyProjIdExternalKeystringNoThe line's project's alternate key in ExternalSystem, used in place of ProjId.
Category IDCategoryIdstringYesProject category
QuantityQtydecimalYesHours, quantity, or units
Cost PriceCostPricedecimalNoCost price per unit
Sales PriceSalesPricedecimalNoSales/billing price per unit
Currency CodeCurrencyCodestringNoTransaction currency
DescriptionDescriptionstringNoLine description
Transaction DateTransDatedateNoLine date (overrides header)
Worker Personnel NumberWorkerPersonnelNumberstringNoPersonnel number of the worker the line is for (its resource); an unknown number fails with ValidationFailed
Item IDItemIdstringItem journalsItem number consumed onto the project
Item ID keyItemIdExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemId.
Inventory Dimension IDInventDimIdstringNoItem journals: the dimension (site / warehouse ...) the item is consumed from; empty = the item's default order settings
Line Property IDLinePropertyIdstringNoBillable / NonBill ...; empty = the project line property setup default
Offset Main Account IDOffsetMainAccountIdstringExpense journalsMain account the expense is paid from (credit side; the project side comes from the project posting setup)
Activity NumberActivityNumberstringNoProject activity number
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProjId": "000001",
"JournalNameId": "Hour",
"Description": "Weekly timesheet entries",
"PostingDate": "2026-01-15",
"Lines": [
{
"CategoryId": "Journeyman",
"Qty": 8.0,
"CostPrice": 75.00,
"SalesPrice": 150.00,
"CurrencyCode": "USD",
"Description": "Development work",
"WorkerPersonnelNumber": "000020"
}
]
}
}

13. Project Invoice Service​

Service: MGCLatticeProjectInvoiceService Service Group: MGCLatticeProjectServiceGroup

createInvoiceProposal​

Creates a project invoice proposal and, with PostAfterCreate, posts it. DocumentId is the proposal; PostedDocumentId is the posted invoice (with PostAfterCreate) or the proposal.

The proposal is created the way the periodic Create invoice proposals job creates one (ProjInvoiceProposalNormalPeriodic::createInvoiceProposalLines): it takes the project's posted, chargeable hour, expense, item, fee and on-account transactions up to the invoice date that are not invoiced yet. If there are none, no proposal is created and the operation fails with a BusinessRule error. A ProjId that names no project returns DocumentNotFound. With PostAfterCreate, the proposal is posted through the project invoice form letter, as the invoice proposal workflow posts it. The operation fails if posting produces no invoice journal, and the success message names both the proposal and the invoice. With PostAfterCreate, a failed post deletes the proposal the operation created and returns its transactions to invoiceable, so a retry with the same RequestId proposes them again.

Request Contract: MGCLatticeProjectInvoiceProposalRequestContract

FieldJSON KeyTypeRequiredDescription
Project IDProjIdstringYesProject to invoice
Project ID keyProjIdExternalKeystringNoThe project's alternate key in ExternalSystem, used in place of ProjId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Invoice DateInvoiceDatedateNoInvoice date. Defaults to today's date in the calling user's time zone.
Post After CreatePostAfterCreatebooleanNoIf true, automatically posts the created proposal
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ProjId": "000001",
"InvoiceDate": "2026-01-31",
"PostAfterCreate": true
}
}

13a. Expense Report Service​

Service: MGCLatticeExpenseReportService Service Group: MGCLatticeExpenseServiceGroup Security: MGCLatticeExpenseReportServiceMaintain (Expense reports - create and post) grants Invoke on the four operations. It is in MGCLatticeIntegrationServiceOperationsDuty. Besides the privilege, creating a report for a worker follows the delegate rule of expense management (see AccessDenied below).

Expense reports from expense tools: create an expense report with its lines for a worker, optionally submit it to the expense report approval workflow, and post it once the workflow approved it. Reports and lines are created the way the Expense reports page creates them, so the expense categories, payment methods, sales tax defaults, financial dimensions, project rules and expense policies of the legal entity apply. Neither operation has a preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. Both are idempotent on RequestId.

createExpenseReport​

Creates the report (status Draft) and its lines in one transaction. With SubmitToWorkflow, the report is then submitted to the expense report workflow that applies to it, as its Submit does, with the standard submit checks (expense policies, budget, itemization, required fields); it is then In review. A request that fails after the report was created deletes the report and its lines again, so a failed request leaves nothing behind and can be sent again with the same RequestId.

Request Contract: MGCLatticeExpenseReportCreateRequestContract

FieldJSON KeyTypeRequiredDescription
Worker Personnel NumberWorkerPersonnelNumberstringNoPersonnel number of the worker the report belongs to; empty = the calling user's worker. The worker must be employed in the legal entity
PurposePurposestringNoPurpose of the report
DescriptionDescriptionstringNoDescription of the report
LocationLocationstringNoLocation (destination)
DimensionsDimensionsMGCLatticeDimensionValueContract[]NoFinancial dimensions of the report, merged over the worker's default dimensions
LinesLinesMGCLatticeExpenseReportLineContract[]YesAt least one line
Submit To WorkflowSubmitToWorkflowbooleanNotrue submits the report to its expense report workflow after it is created. Default false
CommentCommentstringNoWorkflow comment of the submit
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Line Contract: MGCLatticeExpenseReportLineContract

FieldJSON KeyTypeRequiredDescription
Category IDCategoryIdstringYesExpense category. On a line with a project it is also the project category, so it must be a category used in projects
Transaction DateTransDatedateNoDate of the expense. Defaults to today
AmountAmountdecimalYesAmount in CurrencyCode; not zero
Currency CodeCurrencyCodestringNoDefaults to the legal entity's accounting currency
Payment MethodPaymentMethodstringNoDefaults to the category's default payment method. Must be allowed for the category
MerchantMerchantstringNoMerchant
DescriptionDescriptionstringNoDefaults to the category's description
Business PurposeBusinessPurposestringNoBusiness purpose
Additional InformationAdditionalInformationstringNoAdditional information
Sales Tax GroupSalesTaxGroupstringNoDefaults to the group the expense line defaults (worker, project, tax setup)
Item Sales Tax GroupItemSalesTaxGroupstringNoDefaults to the category's item sales tax group
Project IDProjIdstringNoProject the expense is charged to
Activity NumberActivityNumberstringNoProject activity; only with ProjId
DimensionsDimensionsMGCLatticeDimensionValueContract[]NoFinancial dimensions of the line, merged over the dimensions it defaults from the report, worker and project
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"WorkerPersonnelNumber": "000020",
"Purpose": "Customer visit Chicago",
"Lines": [
{
"CategoryId": "Taxi",
"TransDate": "2026-10-20",
"Amount": 42.50,
"CurrencyCode": "USD",
"PaymentMethod": "Cash",
"Merchant": "City Cab",
"Description": "Airport to client"
},
{
"CategoryId": "Travel",
"Amount": 22.25,
"PaymentMethod": "Cash",
"ProjId": "000184",
"Description": "Parking at the project site"
}
],
"SubmitToWorkflow": true,
"Comment": "Chicago trip"
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the expense report number. With SubmitToWorkflow, PostedDocumentId is the correlation id of the workflow instance (lower case, without braces): the key that approveWorkItem, rejectWorkItem, delegateWorkItem, recallWorkflow and getWorkflowStatus take (see 10. Workflow Action Service).

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No RequestId or LegalEntityId; no lines; an empty line; no CategoryId; an unknown or inactive category; a zero amount; an unknown currency, payment method, sales tax group, item sales tax group, project or activity; a payment method the category does not allow; a category without a usable default payment method and no PaymentMethod; a project on a category not used in projects; ActivityNumber without ProjId; an unknown worker; a worker not employed in the legal entity; no WorkerPersonnelNumber and the calling user has no worker
DimensionValueNotFound (5)An unknown financial dimension or value
AccessDenied (14)The caller may not file expenses for the worker: only the worker's own user, a current delegate of the worker, or a user with the expense administrator, expense agent or system administrator role may
ConfigurationMissing (11)No expense report number sequence; with SubmitToWorkflow, no expense report workflow applies to the report
BusinessRule (4)The standard line or report validation, or the standard submit checks (expense policies, budget, itemization, required fields), refused the report; the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: createExpenseReportBatch takes a _requests list of MGCLatticeExpenseReportCreateRequestContract and returns MGCLatticeBulkOperationResponseContract with one result per report (see 19. Bulk Operations).

postExpenseReport​

Posts an approved expense report the way the report's Post does: the vendor, ledger or bank transactions of each line's payment method (employee-paid lines to the worker's expense vendor account), the project cost transactions of project lines, sales tax, and the report and lines set to Posted. The whole report posts in one transaction, or nothing does. Lines post on their own transaction dates (moved to the next open date when that period is on hold or closed) unless the expense management parameters say to post on the posting date. When an automatic posting workflow applies, the workflow posts the report itself.

Request Contract: MGCLatticeExpenseReportPostRequestContract

FieldJSON KeyTypeRequiredDescription
Expense Report NumberExpenseReportNumberstringYesThe expense report to post
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "5e2f8a17-9c34-4b61-a0d8-7f1e2b3c4d5e",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ExpenseReportNumber": "000123"
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the expense report number; PostedDocumentId is the posting voucher of the first line. Each line can post under its own voucher (USMF posts one voucher per line); the message lists every voucher.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No ExpenseReportNumber, RequestId or LegalEntityId
DocumentNotFound (2)No such expense report in the legal entity
InvalidStatus (3)The report is already posted; the report is not approved (the message names its status: Draft, In review, Returned, Canceled, ...); a line is not approved
ConfigurationMissing (11)No expense voucher number sequence
BusinessRule (4)The standard posting checks or the posting refused the report (payment method without offset account, project, exchange rate, closed period, budget); the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: postExpenseReportBatch takes a _requests list of MGCLatticeExpenseReportPostRequestContract and returns MGCLatticeBulkOperationResponseContract with one result per report (see 19. Bulk Operations). Neither batch operation is registered for async execution.

Receipts​

The Lattice document attachment entities cannot attach receipts to expense reports: none of them covers expense reports or expense lines. Attach a receipt with the standard ExpAttachedDocuments entity, which attaches a file to an expense line by its ExpTransNumber (read the expense transaction numbers of a report from the standard Expenses entity, filtered by ExpenseReportNumber). That entity stores the receipt in the receipts of the calling user's worker first, so call it as the worker's own user (or as a user whose worker may hold the receipt).


14. Fixed Asset Service​

Service: MGCLatticeFixedAssetService Service Group: MGCLatticeFixedAssetsServiceGroup Security: MGCLatticeFixedAssetsServiceMaintain (Fixed assets integration service operations, in MGCLatticeIntegrationServiceOperationsDuty) grants postAcquisition, runDepreciationProposal, postAssetTransaction, transferAsset, splitAsset and their batch twins. Two high-risk privileges in MGCLatticeIntegrationServiceHighRiskDuty grant the rest: MGCLatticeFixedAssetsDisposalMaintain (Fixed assets - post disposal (high-risk)) grants postDisposal and its batch, and MGCLatticeFixedAssetsReverseMaintain (Fixed assets - reverse transactions (high-risk)) grants reverseAssetTransaction and its batch.

Every fixed asset operation refuses PreviewMode: true with PreviewUnsupported and is idempotent on RequestId. runDepreciationProposal, postAcquisition, postDisposal and postAssetTransaction can also be queued with submitAsyncOperation (see 21. Async Operations).

postAcquisition​

Creates and posts a fixed asset acquisition journal with one or more asset lines. An empty (null) line and a line without AssetBookId or AcquisitionAmount are refused with ValidationFailed before the journal is created. An OffsetMainAccountId that does not resolve in the legal entity's chart of accounts fails the request with DimensionValueNotFound. Success is reported only when the journal is posted; DocumentId and PostedDocumentId are the journal number. The journal carries the request's Description. Each line posts to its own book only: unlike a line entered on the fixed asset journal page, it does not pass the acquisition on to the book's derived books, so acquire a derived book with a line of its own.

Request Contract: MGCLatticeFixedAssetAcquisitionRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesFixed asset journal name
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoAcquisition date. Defaults to system date.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
LinesLinesMGCLatticeFixedAssetAcquisitionLineContract[]YesAt least one acquisition line required

Line Contract: MGCLatticeFixedAssetAcquisitionLineContract

FieldJSON KeyTypeRequiredDescription
Asset IDAssetIdstringYesFixed asset number
Asset ID keyAssetIdExternalKeystringNoThe fixed asset's alternate key in ExternalSystem, used in place of AssetId.
Asset Book IDAssetBookIdstringYesDepreciation book ID
Acquisition AmountAcquisitionAmountdecimalYesPurchase/acquisition cost; not zero
Currency CodeCurrencyCodestringNoTransaction currency. Defaults to the accounting currency
Offset Main AccountOffsetMainAccountIdstringNoOffset GL account
DescriptionDescriptionstringNoLine description
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "FACur",
"Description": "Asset acquisition batch",
"PostingDate": "2026-01-15",
"Lines": [
{
"AssetId": "COMP-000001",
"AssetBookId": "200_SL_CY",
"AcquisitionAmount": 15000.00,
"CurrencyCode": "USD",
"OffsetMainAccountId": "110110",
"Description": "Laptop acquisition"
}
]
}
}

runDepreciationProposal​

Runs the standard depreciation proposal (the fixed asset journal's Proposals > Depreciation proposal) into a new fixed asset journal: one line per asset book with depreciation due through DepreciationDate, optionally only for one AssetBookId. The journal name must be a fixed asset journal name with a voucher series; another journal type fails with ValidationFailed and an unknown asset book with DocumentNotFound. The journal is not posted. DocumentId and PostedDocumentId are the journal number, and the message gives the number of proposed lines or says that nothing was due (the journal then has no lines; any error the proposal reported is in InformationalMessages).

The operation does not create the proposal header that the enhanced depreciation proposal page lists: Microsoft creates that header only from its own dialog and journal form, and only when the "enhanced asset proposal form" preview feature is enabled. Proposals created through the service appear as fixed asset journals.

Request Contract: MGCLatticeFixedAssetDepreciationRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesFixed asset journal name
Asset Book IDAssetBookIdstringNoDepreciation book to process; empty for every book
Depreciation DateDepreciationDatedateNoRun depreciation through this date. Defaults to system date.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "FACur",
"AssetBookId": "200_SL_CY",
"DepreciationDate": "2026-01-31"
}
}

postDisposal​

Posts a fixed asset disposal (sale or scrap) via journal. A request without AssetBookId is refused with ValidationFailed. Success is reported only when the journal is posted; DocumentId and PostedDocumentId are the disposal journal's number. Like postAcquisition, the disposal posts to the named book only, not to its derived books.

Request Contract: MGCLatticeFixedAssetDisposalRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesFixed asset journal name
Asset IDAssetIdstringYesFixed asset to dispose
Asset ID keyAssetIdExternalKeystringNoThe fixed asset's alternate key in ExternalSystem, used in place of AssetId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Asset Book IDAssetBookIdstringYesDepreciation book
Is SaleIsSalebooleanNotrue for disposal-sale, false (the default when omitted) for disposal-scrap
Sale AmountSaleAmountdecimalNoSale proceeds (only applicable when IsSale is true)
Offset Main AccountOffsetMainAccountIdstringNoOffset main account for the sale proceeds; one that does not resolve fails the request with DimensionValueNotFound
Currency CodeCurrencyCodestringNoTransaction currency. Defaults to the accounting currency
Disposal DateDisposalDatedateNoDisposal date. Defaults to system date.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "FACur",
"AssetId": "COMP-000001",
"AssetBookId": "200_SL_CY",
"IsSale": true,
"SaleAmount": 5000.00,
"CurrencyCode": "USD",
"DisposalDate": "2026-01-15"
}
}

postAssetTransaction​

Posts fixed asset transactions after acquisition in a new fixed asset journal, as the fixed asset journal page posts them: acquisition adjustments, depreciation, depreciation adjustments, revaluations, write-up and write-down adjustments, extraordinary depreciation and bonus depreciation. Each line is created the way the standard fixed asset proposals create journal lines: the asset is the account; the book's posting profile gives the offset account for the transaction type (unless the line names one); the line takes the book's financial dimensions and the standard text and voucher. Derived books of the line's book take the transaction as the standard journal passes it to them, except a derived book that is not acquired. Every line is checked before the journal is created. The journal is posted, and success is reported only when it is posted; a journal that does not post is deleted. DocumentId is the posted journal, PostedDocumentId the voucher of its first line; the message lists every voucher.

Request Contract: MGCLatticeFixedAssetTransactionRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesA fixed asset journal name; its posting layer must be the posting layer of every line's book
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoDefault transaction date of the lines. Defaults to today
External SystemExternalSystemstringNoThe external system of the lines' AssetIdExternalKey. See Cross-reference keys.
LinesLinesMGCLatticeFixedAssetTransactionLineContract[]YesAt least one line
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported

Line Contract: MGCLatticeFixedAssetTransactionLineContract

FieldJSON KeyTypeRequiredDescription
Asset IDAssetIdstringYesFixed asset
Asset ID keyAssetIdExternalKeystringNoThe asset's alternate key in ExternalSystem, used in place of AssetId.
Asset Book IDAssetBookIdstringYesBook of the asset; it must be acquired
Transaction TypeTransactionTypestringYesAcquisitionAdj, Depreciation, DepreciationAdj, Revaluation, WriteUpAdj, WriteDownAdj, ExtraordinaryDepreciation or BonusDepreciation (not case-sensitive). Acquisitions are posted with postAcquisition, disposals with postDisposal
Debit AmountDebitAmountdecimalOne of the twoAmount in the accounting currency that increases the book's value
Credit AmountCreditAmountdecimalOne of the twoAmount in the accounting currency that decreases the book's value (a depreciation or write-down is a credit)
Transaction DateTransactionDatedateNoDefaults to PostingDate
Offset Main AccountOffsetMainAccountIdstringNoOffset main account. Defaults to the posting profile's offset account for the type and book
DimensionsDimensionsMGCLatticeDimensionValueContract[]NoReplace these dimensions of the book's financial dimensions on the line; the other dimensions keep their values
Consumption QuantityConsumptionQuantitydecimalNoConsumption of a depreciation line of a book that depreciates by consumption
Reason CodeReasonCodestringNoFinancial reason; required when the fixed asset parameters demand a reason for the type
Reason CommentReasonCommentstringNoReason comment
DescriptionDescriptionstringNoLine text. Defaults to the standard fixed asset text
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "FACur",
"PostingDate": "2026-10-31",
"Lines": [
{ "AssetId": "COMP-000171", "AssetBookId": "200_SLLR", "TransactionType": "Depreciation", "CreditAmount": 250.00 },
{ "AssetId": "COMP-000171", "AssetBookId": "200_SLLR", "TransactionType": "WriteDownAdj", "CreditAmount": 500.00,
"ReasonCode": "FA-IMPAIR", "Dimensions": [ { "DimensionName": "Department", "DimensionValue": "023" } ] }
]
}
}

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)A missing member; an unknown journal name or one that is not a fixed asset journal; a book on another posting layer than the journal name; an unknown asset, book or reason code; both amounts or none, or a negative amount; an acquisition, disposal or other transaction type (the message names the operation that posts acquisitions or disposals)
DimensionValueNotFound (5)An offset main account or financial dimension that does not resolve
InvalidStatus (3)A book that is not acquired yet, or a sold or scrapped book
BusinessRule (4)A depreciation type (depreciation, depreciation adjustment, extraordinary or bonus depreciation) on a book that does not depreciate; a posting the standard refuses, with the standard messages in Errors
ConfigurationMissing (11)The book's posting profile has no account, or no offset account, for the transaction type and book (for example bonus depreciation where the profile has no bonus depreciation accounts) and the line and journal name name none; a journal name without a voucher number sequence; no chart of accounts
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: postAssetTransactionBatch takes a _requests list of MGCLatticeFixedAssetTransactionRequestContract; each item runs as postAssetTransaction and gets its own result in MGCLatticeBulkOperationResponseContract (see 19. Bulk Operations). The batch operation is not registered for async execution.

transferAsset​

Transfers a fixed asset to new financial dimensions with the standard asset transfer (the fixed asset page's Transfer asset), and moves it to a new location. For each book the transfer posts a general ledger voucher that moves the book's balance from the current dimensions to the new ones, writes an asset transfer transaction and the transfer history, and gives the book the new dimensions. The dimensions sent replace the same dimensions of each book's current dimensions; the other dimensions keep their values, and a book that already has the result is left as it is. The location is the asset's location. The transfer runs in one transaction. DocumentId is the asset, PostedDocumentId the voucher of the first transferred book (empty when only the location changes); the message lists the books and vouchers.

Request Contract: MGCLatticeFixedAssetTransferRequestContract

FieldJSON KeyTypeRequiredDescription
Asset IDAssetIdstringYesFixed asset
Asset ID keyAssetIdExternalKeystringNoThe asset's alternate key in ExternalSystem, used in place of AssetId.
External SystemExternalSystemstringNoThe external system of AssetIdExternalKey. See Cross-reference keys.
Asset Book IDAssetBookIdstringNoThe one book to transfer. Without it, every open or closed book of the asset that has a posting layer is transferred
DimensionsDimensionsMGCLatticeDimensionValueContract[]One of Dimensions / LocationIdThe financial dimension values the asset moves to
LocationLocationIdstringOne of Dimensions / LocationIdThe fixed asset location the asset moves to
Transfer DateTransferDatedateNoDefaults to today; it must be valid in the fiscal calendar
CommentCommentstringNoTransfer comment, written to the transfer history and transactions
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "4a1b2c3d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"AssetId": "COMP-000171",
"Dimensions": [ { "DimensionName": "Department", "DimensionValue": "023" } ],
"LocationId": "PROD",
"TransferDate": "2026-10-31",
"Comment": "Moved to production"
}
}

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No AssetId; neither dimensions nor location; an unknown location or book; a book without a posting layer; a request that would change nothing
DimensionValueNotFound (5)A dimension that does not resolve
DocumentNotFound (2)An unknown asset
InvalidStatus (3)A book that is not open or closed, or an asset with no such book
BusinessRule (4)A transfer date outside the fiscal calendar; a book with no transactions to move; a public sector transfer between balancing dimensions (it needs due to and due from accounts: transfer it on the page)
ConfigurationMissing (11)No transfer number sequence in the fixed asset parameters
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: transferAssetBatch takes a _requests list of MGCLatticeFixedAssetTransferRequestContract; each item runs as transferAsset and gets its own result.

splitAsset​

Splits a fixed asset book with the standard asset split (the book's Split asset) and posts the split journal it creates, in one transaction: the percentage of the book's acquisition, depreciation and other values moves to a book of the receiving asset. Without ToAssetId the receiving asset is created as a copy of the asset (the standard Copy fixed asset: same group and details, every book copied, none acquired). A Quantity is turned into the percentage it is of the asset's quantity, and the quantity moves to the receiving asset (a new asset gets exactly that quantity); a Percent split moves values only. Derived books the split asset has not acquired are left out of the split. Nothing is kept when the split journal does not post. DocumentId is the asset that was split, PostedDocumentId the asset that received the split; the message names the posted split journal.

Request Contract: MGCLatticeFixedAssetSplitRequestContract

FieldJSON KeyTypeRequiredDescription
Asset IDAssetIdstringYesFixed asset to split
Asset ID keyAssetIdExternalKeystringNoThe asset's alternate key in ExternalSystem, used in place of AssetId.
Asset Book IDAssetBookIdstringYesBook to split; it must be acquired
To Asset IDToAssetIdstringNoExisting asset that receives the split. Empty creates a new asset
To Asset ID keyToAssetIdExternalKeystringNoThe receiving asset's alternate key in ExternalSystem, used in place of ToAssetId.
To Asset Book IDToAssetBookIdstringNoBook of the receiving asset. Defaults to AssetBookId
PercentPercentdecimalOne of Percent / QuantityShare to split off, greater than 0 and at most 100
QuantityQuantitydecimalOne of Percent / QuantityUnits to split off, at most the asset's quantity
Split DateSplitDatedateNoDefaults to today
Journal Name IDJournalNameIdstringYesFixed asset journal name of the split journal, on the books' posting layer
External SystemExternalSystemstringNoThe external system of the keys. See Cross-reference keys.
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "8d7c6b5a-4f3e-4d2c-9b1a-0f9e8d7c6b5a",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"AssetId": "COMP-000171",
"AssetBookId": "200_SLLR",
"Quantity": 4,
"SplitDate": "2026-10-31",
"JournalNameId": "FACur"
}
}

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)A missing member; Percent and Quantity together or neither; a percentage or quantity out of range; an asset without a quantity for a quantity split; an unknown journal name, or one that is not a fixed asset journal or posts to another layer; an unknown book or receiving asset; the asset itself as receiving asset; books that differ in posting to the general ledger
DocumentNotFound (2)An unknown asset
InvalidStatus (3)A book that is not acquired, or a sold or scrapped book
BusinessRule (4)A split or posting the standard refuses, with the standard messages in Errors
ConfigurationMissing (11)A new asset in a group that numbers its assets manually; a journal name without a voucher number sequence
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: splitAssetBatch takes a _requests list of MGCLatticeFixedAssetSplitRequestContract; each item runs as splitAsset and gets its own result.

reverseAssetTransaction​

Reverses a posted fixed asset voucher of a book with the standard fixed asset transaction reversal (the fixed asset transactions page's Reverse transaction): the general ledger voucher and every asset transaction of the voucher are reversed, and the book is updated as the standard reversal updates it, in one transaction. DocumentId is the reversed voucher, PostedDocumentId the reversal voucher.

Request Contract: MGCLatticeFixedAssetReversalRequestContract

FieldJSON KeyTypeRequiredDescription
Asset IDAssetIdstringYesFixed asset
Asset ID keyAssetIdExternalKeystringNoThe asset's alternate key in ExternalSystem, used in place of AssetId.
Asset Book IDAssetBookIdstringYesBook of the transaction
VoucherVoucherstringYesVoucher of the transaction to reverse
Transaction DateTransactionDatedateNoNeeded only when the voucher has transactions of the book on several dates
Reversal DateReversalDatedateNoDefaults to today; not before the transaction's date
Reason CodeReasonCodestringNoFinancial reason written on the reversal
Reason CommentReasonCommentstringNoReason comment
External SystemExternalSystemstringNoThe external system of AssetIdExternalKey. See Cross-reference keys.
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "6f5e4d3c-2b1a-4c9d-8e7f-6a5b4c3d2e1f",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"AssetId": "COMP-000171",
"AssetBookId": "200_SLLR",
"Voucher": "FAJ-000318",
"ReversalDate": "2026-11-02",
"ReasonCode": "ERROR",
"ReasonComment": "Depreciation posted twice"
}
}

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)A missing member; an unknown asset, book or reason code; a voucher with transactions on several dates and no TransactionDate; a reversal date before the transaction
DocumentNotFound (2)No transaction of the book with that voucher
InvalidStatus (3)A transaction already reversed, or itself a reversal
BusinessRule (4)A voucher posted with a vendor or customer transaction (reverse it in accounts payable or receivable); a reversal the standard refuses, for example a later depreciation on the book, a later transfer, a negative net book value or a closed fiscal period, with the standard messages
ConfigurationMissing (11)No reversal voucher or trace number sequence in the general ledger parameters
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: reverseAssetTransactionBatch takes a _requests list of MGCLatticeFixedAssetReversalRequestContract; each item runs as reverseAssetTransaction and gets its own result.

Security: high-risk. reverseAssetTransaction and its batch are granted only by MGCLatticeFixedAssetsReverseMaintain (Fixed assets - reverse transactions (high-risk)), which is in MGCLatticeIntegrationServiceHighRiskDuty; MGCLatticeFixedAssetsServiceMaintain does not grant them.


15. Vendor Payment Proposal Service​

Service: MGCLatticeVendorPaymentProposalService Service Group: MGCLatticeAccountsPayableServiceGroup

generatePaymentProposal​

Creates a vendor payment journal and fills it with the standard vendor payment proposal: the open, approved vendor transactions due from FromDueDate through ToDueDate, optionally only those with MethodOfPayment, are proposed and transferred to the journal as payment lines, as Payment proposal followed by Transfer does on the journal page. The journal is not posted. DocumentId and PostedDocumentId are the journal number, and the message gives the number of payment lines. When nothing matches, no journal is kept - the empty journal is deleted again, as the standard proposal's "avoid empty journals" does - the response succeeds with an empty DocumentId and the message says so. A failure after the journal was created deletes it too while it has no lines.

The journal name must be a vendor payment journal name (type Payment, USMF VendPay) with a voucher series; another type, or FromDueDate later than ToDueDate, fails with ValidationFailed, and an unknown MethodOfPayment with DocumentNotFound.

Request Contract: MGCLatticeVendorPaymentProposalRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesVendor payment journal name
From Due DateFromDueDatedateNoInclude transactions due on or after this date; empty for no lower bound
To Due DateToDueDatedateNoInclude transactions due on or before this date. Defaults to today's date in the calling user's time zone.
Method of PaymentMethodOfPaymentstringNoOnly transactions with this method of payment
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "VendPay",
"FromDueDate": "2026-01-01",
"ToDueDate": "2026-01-31",
"MethodOfPayment": "CHECK"
}
}

generateVendorPayments​

Generates the payments of an open vendor payment journal the way the journal lines page's Generate payments does, for check payments: each line gets the next check number of its bank account's check layout as payment reference, its payment status becomes Sent, and the check is recorded in the bank account's checks (Cash and bank management > Checks) with status Payment, the payment voucher, the vendor and the amount. With PostAfterGenerate the journal is then posted, in the same transaction: if the posting fails, nothing is generated either (no check is used). Typical use: after generatePaymentProposal created the journal. Each generated check fires the Lattice vendor check issued business event.

Which lines are generated: the vendor lines with payment status None or Rejected - with MethodOfPayment, the lines with that method (as the dialog asks for one method); without it, every line whose method of payment needs generation before it can post (payment type Check, a check number demanded by the method's payment control, or payment status Sent demanded). Lines that post without generation (for example USMF ELECTRONIC) are left as they are. With BankAccountId, only the lines that pay from that bank account. A line's check is drawn on the bank account it pays from (its offset bank account).

The check document itself is not printed: the standard check report prints only to a network printer or to a file sent to the user's browser, which a service call cannot use. Print the checks from F&O when needed (the journal's Print > Check copy, or the bank account's checks). Methods of payment that export a payment file (a file format or an Electronic reporting format) are refused: generate those payments in the vendor payment journal. The operation has no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. It is idempotent on RequestId.

Request Contract: MGCLatticeVendorPaymentGenerationRequestContract

FieldJSON KeyTypeRequiredDescription
Journal NumberJournalNumstringOne of JournalNum / JournalNumExternalKeyAn open vendor payment journal
Journal Number keyJournalNumExternalKeystringNoThe journal's alternate key in ExternalSystem, used in place of JournalNum.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with JournalNumExternalKey. See Cross-reference keys.
Method of PaymentMethodOfPaymentstringNoOnly the lines with this method; without it, the lines whose method needs generation
Bank Account IDBankAccountIdstringNoOnly the lines that pay from this bank account; it needs a check layout
Post After GeneratePostAfterGeneratebooleanNotrue posts the journal after the generation, in the same transaction. Default false
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNum": "00698",
"MethodOfPayment": "CHECK",
"PostAfterGenerate": true
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the journal; PostedDocumentId is the first payment voucher when the journal was posted, otherwise the first check number. Message lists every check number; InformationalMessages has one line per check: check number, vendor, amount and currency, voucher and bank account.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No JournalNum; a journal that is not a vendor payment journal; an unknown method of payment or bank account; an inactive bank account; a line that pays from no bank account; a method of payment that exports a payment file or uses an Electronic reporting format; a journal without lines or without a line to generate
DocumentNotFound (2)An unknown journal
InvalidStatus (3)The journal is posted, blocked by the system or by another user, or needs workflow approval and is not approved; its payments are already generated
ConfigurationMissing (11)The method of payment has no export format; the bank account has no check layout; a fixed check numbering has no created checks left
BusinessRule (4)The standard generation skipped a line (its messages in Errors), or the posting failed
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: generateVendorPaymentsBatch takes a _requests list of MGCLatticeVendorPaymentGenerationRequestContract and returns MGCLatticeBulkOperationResponseContract with one result per journal (see 19. Bulk Operations).

Security: generateVendorPayments and its batch are granted by MGCLatticeAccountsPayableServiceMaintain (Accounts payable integration service operations), with generatePaymentProposal. To post check payments in one call instead, use postVendorPaymentJournal with GeneratePayments (see 9. Payment Journal Service); a generated check is reversed with reverseVendorPayment.


16. Vendor Invoice Journal Service​

Service: MGCLatticeVendorInvoiceJournalService Service Group: MGCLatticeAccountsPayableServiceGroup

postInvoiceRegisterJournal / postInvoiceApprovalJournal​

F&O has two ways to enter a vendor invoice, and postInvoiceRegisterJournal takes both journal types:

JournalNameId typeUSMF exampleWhat posting does
Invoice register (PurchaseLedger)APInvRegPosts each invoice to the vendor posting profile's pending-invoice (purchasing offset) account and parks it, unapproved, in the vendor invoice pool. Leave OffsetMainAccountId empty to get that account, as F&O does. Approve the invoice with postInvoiceApprovalJournal.
Vendor invoice journal (VendInvoiceRegister, "Vendor invoice recording")APInvoicePosts each invoice outright, approved, against OffsetMainAccountId (typically the expense account). There is nothing to approve; the posted invoice is open for payment proposals and payment journals.

Any other type fails with "Journal name … is not a Vendor invoice register journal (an invoice register or a vendor invoice journal)". In both operations, an empty (null) line is refused with ValidationFailed before any journal is created. postInvoiceRegisterJournal also refuses a line whose VendAccount is not an existing vendor that way; an approval line with an unknown vendor finds no registered invoice and fails with DocumentNotFound. Every register line needs an approver ("Approved by"): ApproverPersonnelNumber, else the worker mapped to the calling user. Each line takes the vendor's defaults, as the journal page does when the vendor is entered: terms of payment, method of payment (and its bank transaction type), payment specification and id, cash discount (calculated on the line) and bank account, the vendor's currency when CurrencyCode is empty, and - when DueDate is empty - the due date from the vendor's terms of payment (from InvoiceDate when sent, else the transaction date). Both operations return the journal number in DocumentId and PostedDocumentId; the journal carries the request's Description.

postInvoiceApprovalJournal approves invoices registered through an invoice register journal - the service form of opening an invoice approval journal, choosing Find vouchers, entering the expense account and posting. JournalNameId must be an Approval journal name (USMF APInvApp). For each line (one per invoice) the service:

  1. finds the registered invoice (VendAccount + InvoiceId) in the vendor invoice pool;
  2. fetches it into a new approval journal, which brings in the lines that reverse the pending posting;
  3. adds the expense line on OffsetMainAccountId (required) for the registered amount, approved by the register's approver or ApproverPersonnelNumber;
  4. posts the journal and checks that every invoice is now approved. DocumentId is the approval journal number.

AmountCurCredit / AmountCurDebit are optional on an approval line; when given they must equal the registered amount. The operation fails without posting - the invoice stays in the pool - when the invoice does not exist, was posted outright through a vendor invoice journal ("never through an invoice register, so there is nothing to approve"), is already approved, is held by another unposted approval journal, or the amount differs. If posting itself fails, the fetched invoices are returned to the pool, so the approval can be retried. Not supported: splitting one invoice over several expense accounts, a posting date other than the register's, and sales tax recalculation.

Request Contract: MGCLatticeVendorInvoiceJournalPostRequestContract

FieldJSON KeyTypeRequiredDescription
Journal Name IDJournalNameIdstringYesRegister: an invoice register or vendor invoice journal name. Approval: an Approval journal name
DescriptionDescriptionstringNoJournal description
Posting DatePostingDatedateNoDefault transaction date
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
LinesLinesMGCLatticeVendorInvoiceJournalLineContract[]YesAt least one line required

Line Contract: MGCLatticeVendorInvoiceJournalLineContract

FieldJSON KeyTypeRequiredDescription
Vendor AccountVendAccountstringYesVendor account number
Vendor Account keyVendAccountExternalKeystringNoThe vendor's alternate key in ExternalSystem, used in place of VendAccount.
Invoice IDInvoiceIdstringNoVendor invoice number. Required on an approval line
Debit AmountAmountCurDebitdecimalNoDebit amount
Credit AmountAmountCurCreditdecimalNoCredit amount
Currency CodeCurrencyCodestringNoTransaction currency. Defaults to the vendor's currency
DescriptionDescriptionstringNoLine description
Transaction DateTransDatedateNoLine date
Invoice DateInvoiceDatedateNoVendor invoice date (DocumentDate)
Due DateDueDatedateNoPayment due date. Defaults from the vendor's terms of payment
Offset Main Account IDOffsetMainAccountIdstringSee descriptionVendor invoice journal: the offset (expense) main account. Invoice register: leave empty for the pending-invoice account. Approval: required, the expense account
ApproverApproverPersonnelNumberstringNo"Approved by" worker. Register: defaults to the calling user's worker. Approval: overrides the register's approver

Register an invoice for approval:

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "APInvReg",
"Description": "Vendor invoice register",
"PostingDate": "2026-01-15",
"Lines": [
{
"VendAccount": "US-101",
"InvoiceId": "VINV-2026-001",
"AmountCurCredit": 7500.00,
"CurrencyCode": "USD",
"Description": "Office supplies invoice",
"InvoiceDate": "2026-01-10",
"DueDate": "2026-02-10",
"ApproverPersonnelNumber": "000020"
}
]
}
}

Approve it to an expense account (postInvoiceApprovalJournal):

{
"_request": {
"RequestId": "0b7c8d44-6f3a-4a5e-9d1e-5a2f3c4b6d71",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "APInvApp",
"Description": "Vendor invoice approval",
"Lines": [
{
"VendAccount": "US-101",
"InvoiceId": "VINV-2026-001",
"AmountCurCredit": 7500.00,
"CurrencyCode": "USD",
"OffsetMainAccountId": "601500"
}
]
}
}

To post an invoice outright instead, send the first request with a vendor invoice journal name (USMF APInvoice) and the expense account in OffsetMainAccountId.


16a. Vendor Invoice Service​

Service: MGCLatticeVendorInvoiceService Service Group: MGCLatticeAccountsPayableServiceGroup

postPendingVendorInvoice​

Posts a pending vendor invoice (Accounts payable > Invoices > Pending vendor invoices), with or without purchase order lines, the way the page's Post does: the standard invoice posting runs on the saved invoice, so invoice matching, invoice policies, the vendor invoice approval workflow rule and every posting check are the standard ones. The invoice posts on its own posting date and invoice date (the accounts payable parameter "Posting date adjustment" applies as it does on the page). It posts completely or not at all: on a refusal the invoice stays pending as it was.

Create the pending invoice first, in D365 or through the standard VendorInvoiceHeaders and VendorInvoiceLines entities (plus InvoiceSubLinesV2 to match a purchase order line to its product receipts). If a vendor invoice approval workflow applies to the invoice, it must be approved before it can be posted. Name the invoice either by HeaderReference or by VendorAccount with InvoiceNumber, not both. The operation has no preview: PreviewMode: true is refused with PreviewUnsupported before anything runs. It is idempotent on RequestId.

Request Contract: MGCLatticePendingVendorInvoicePostRequestContract

FieldJSON KeyTypeRequiredDescription
Header ReferenceHeaderReferencestringOne of HeaderReference / VendorAccount + InvoiceNumberThe pending invoice's header reference (the key of VendorInvoiceHeaders)
Vendor AccountVendorAccountstringWith InvoiceNumberThe invoice's invoice account or vendor account
Vendor Account keyVendorAccountExternalKeystringNoThe vendor's alternate key in ExternalSystem, used in place of VendorAccount.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member. See Cross-reference keys.
Invoice NumberInvoiceNumberstringWith VendorAccountThe vendor's invoice number (the pending invoice's Invoice field)
Preview ModePreviewModebooleanNoNot supported: true is refused with PreviewUnsupported
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"VendorAccount": "US-101",
"InvoiceNumber": "VINV-2026-0042"
}
}

Response: MGCLatticeOrderOperationResponseContract. DocumentId is the vendor's invoice number of the posted invoice; PostedDocumentId is the voucher of the posted vendor invoice (the invoice journal's voucher, which is also the vendor transaction's voucher). The message names both (Pending vendor invoice VINV-2026-0042 of vendor US-101 posted with voucher APINV-000321.). Warnings and information from the posting are in Warnings and InformationalMessages.

Error codes:

ErrorCodeWhen
PreviewUnsupported (10)PreviewMode is true. Refused before any other check
ValidationFailed (1)No RequestId or LegalEntityId, an unknown legal entity; no invoice named, or named both ways; VendorAccount without InvoiceNumber or the reverse; an unknown vendor or a vendor key that does not resolve; several pending invoices of the vendor with that number (the message lists their header references: send HeaderReference)
DocumentNotFound (2)No pending invoice with that header reference, or with that vendor and invoice number
InvalidStatus (3)The invoice is already posted (the message names the voucher); it is open for editing or being posted in another session; it is included in automated invoice processing; it is on hold; it is in the approval workflow, or a vendor invoice workflow applies and the invoice is not approved (the message names the workflow status and the workflow)
BusinessRule (4)The standard posting refused the invoice (matching discrepancies that need approval, invoice policies, a closed period, a duplicate or missing invoice number, accounts, ...); the standard messages are in Errors
TransientRuntime (6)A runtime fault; IsRetryable true

Batch: postPendingVendorInvoiceBatch takes a _requests list of MGCLatticePendingVendorInvoicePostRequestContract and returns MGCLatticeBulkOperationResponseContract with one result per invoice (see 19. Bulk Operations).

Security: both operations are granted by MGCLatticeAccountsPayableServiceMaintain (Accounts payable integration service operations), like invoicePurchaseOrder. They post vendor invoices to the ledger: grant the privilege only to integration identities that may post payables.


17. Currency Revaluation Service​

Service: MGCLatticeCurrencyRevaluationService Service Group: MGCLatticeGeneralLedgerServiceGroup

runCustomerRevaluation / runVendorRevaluation / runLedgerRevaluation​

Runs foreign currency revaluation for customer, vendor, or ledger accounts in the request's legal entity.

  • runCustomerRevaluation / runVendorRevaluation revalue the open customer / vendor transactions at the exchange rate of RevaluationDate, for CurrencyCode or every foreign currency. They have no period or account range: FromDate, MainAccountFromId and MainAccountToId are refused with ValidationFailed.
  • runLedgerRevaluation revalues the general ledger for CurrencyCode, or else for every currency posted to the ledger in the period, from FromDate (default: the start of the fiscal year of RevaluationDate) through RevaluationDate, optionally only for main accounts MainAccountFromId through MainAccountToId. Both dates must fall in one fiscal year. Settings the standard revaluation rejects (for example a FromDate after RevaluationDate) fail the request with ValidationFailed. When no ledger transactions were posted in the period, the operation succeeds and its message says there is nothing to revalue; nothing is posted.

Every operation reports what it posted: when the run posted exchange adjustments, DocumentId and PostedDocumentId are the adjustment voucher and the message names it (for a customer or vendor run, with the number of adjusted transactions); when nothing needed an adjustment, both are empty and the message says nothing was posted.

Request Contract: MGCLatticeCurrencyRevaluationRequestContract

FieldJSON KeyTypeRequiredDescription
Revaluation DateRevaluationDatedateNoRevalue through this date. Defaults to today's date in the calling user's time zone.
From DateFromDatedateNoLedger revaluation only: first date of the period. Defaults to the start of the fiscal year of RevaluationDate.
Currency CodeCurrencyCodestringNoRevalue only this currency
Main Account FromMainAccountFromIdstringNoStart of main account range (ledger revaluation only)
Main Account ToMainAccountToIdstringNoEnd of main account range (ledger revaluation only)

Customer or vendor revaluation:

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"RevaluationDate": "2026-01-31",
"CurrencyCode": "EUR"
}
}

Ledger revaluation with account range:

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"RevaluationDate": "2026-01-31",
"FromDate": "2026-01-01",
"CurrencyCode": "EUR",
"MainAccountFromId": "110110",
"MainAccountToId": "130100"
}
}

18. Purchase Requisition Service​

Service: MGCLatticePurchaseRequisitionService Service Group: MGCLatticeAccountsPayableServiceGroup

In both operations, a PurchReqId that names no purchase requisition in the legal entity returns DocumentNotFound. A requisition is approved through its workflow: submit it, then complete the approver's work item with approveWorkItem (section 10).

submitPurchaseRequisition​

Submits a purchase requisition to its PurchReqReview workflow the way the requisition page's Submit does, with the same document checks and outcomes as submitToWorkflow (section 10): the requisition must be a draft with no workflow in progress (InvalidStatus), have lines and be submitted by its preparer and pass the submission rules (BusinessRule), and a PurchReqReview configuration must apply (ConfigurationMissing). The requisition moves to In review together with the activation. DocumentId is the requisition; the message names the workflow instance (correlation id).

Request Contract: MGCLatticePurchReqActionRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase Requisition IDPurchReqIdstringYesPurchase requisition number
Purchase Requisition ID keyPurchReqIdExternalKeystringNoThe purchase requisition's alternate key in ExternalSystem, used in place of PurchReqId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
CommentCommentstringNoWorkflow submission comment. Defaults to auto-generated message. Submit only
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"PurchReqId": "PR-000001",
"Comment": "Submitted for approval via integration"
}
}

convertPurchaseRequisitionToOrder​

Converts an approved purchase requisition into one or more purchase orders using the standard conversion engine. DocumentId is the requisition; PostedDocumentId is the first purchase order created, and the message lists all of them. An approved requisition with no lines left to convert is refused with ValidationFailed; a conversion that creates no purchase order line fails with BusinessRule. When the purchasing policy has automatic purchase order creation, D365 releases the approved requisition to a purchase order itself (status Closed), and convert then answers InvalidStatus.

Request Contract: MGCLatticePurchReqActionRequestContract

FieldJSON KeyTypeRequiredDescription
Purchase Requisition IDPurchReqIdstringYesPurchase requisition number (must be in Approved status; InvalidStatus otherwise)
Purchase Requisition ID keyPurchReqIdExternalKeystringNoThe purchase requisition's alternate key in ExternalSystem, used in place of PurchReqId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"PurchReqId": "PR-000001"
}
}

Error Handling​

All operations use a consistent error handling pattern:

  1. Validation errors -- A request that fails its checks (missing or blank fields, empty or missing lines, invalid quantities or dates, unknown codes or accounts the caller supplied, contract rules) returns ValidationFailed, or a more specific code: DocumentNotFound, ConfigurationMissing, InvalidStatus, DimensionValueNotFound. Not retryable. Returns Success: false, Status: 4 (Failed), with the error message in both Message and Errors[].

  2. Business rule errors -- A failure of the business processing after the request is accepted, for example D365 refusing to create or post the document, returns BusinessRule, not retryable. The captured infolog errors are in Errors[].

  3. Runtime errors -- Runtime (CLR), deadlock and update-conflict failures return TransientRuntime, retryable, with a generic runtime error message.

  4. Unexpected errors -- An exception that is not an error, CLR error, deadlock or update conflict returns the message Operation <name> failed due to an unexpected error., classified UnexpectedError, not retryable (see Unexpected Error).

  5. Transaction safety -- All operations wrap posting logic in ttsBegin/ttsCommit blocks. On failure, any active transaction is safely aborted before returning the error response. The service never throws unhandled exceptions to the caller.

  6. No document left behind -- An operation that creates a document and then posts it (general, intercompany, payment, inventory, project and fixed asset journals, the vendor invoice register journal, free text invoices and their correcting invoices, budget register entries, trade agreement journals, project invoice proposals created with PostAfterCreate) deletes the unposted document again when the post fails; createExpenseReport likewise deletes the expense report it created when the submit to workflow fails. The failed request releases its RequestId, so a resend creates the document anew and nothing is entered twice. A posted document is never deleted; if the cleanup itself fails, the unposted document stays for you to post or delete. Documents an operation deliberately leaves for you to post (the vendor payment proposal journal, the depreciation proposal journal, a project invoice proposal without PostAfterCreate, a check reversal journal left for review) are not affected. The journal posting operations (8a) post journals that already exist and never delete them: a journal that does not post stays as it was.

Example Error Response​

{
"Success": false,
"Status": 4,
"Message": "Sales order SO-999999 was not found.",
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"ExecutionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"DocumentId": "",
"StartDateTimeUtc": "2026-01-15T10:30:00.000Z",
"EndDateTimeUtc": "2026-01-15T10:30:00.050Z",
"DurationMs": 50,
"Errors": ["Sales order SO-999999 was not found."],
"Warnings": [],
"InformationalMessages": []
}

19. Bulk Operations​

The posting and action operations have a *Batch variant that accepts a list of requests and returns MGCLatticeBulkOperationResponseContract: append Batch to the operation name. The status queries and the async, price inquiry, database access and DMF configuration operations have no batch variant. setSalesPriceBatch returns its own envelope, MGCLatticeSetSalesPriceBatchResult, instead (see 28. Sales Trade Agreement Service).

Endpoint Pattern:

POST {baseUrl}/api/services/{ServiceGroup}/{ServiceName}/{operationName}Batch

Request Format​

The bulk operation takes a _requests list; each item is the same request contract the base operation takes, with its own RequestId:

{
"_requests": [
{
"RequestId": "a1b2c3d4-0001-0000-0000-000000000001",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"SalesOrderId": "SO-000123",
"PostingDate": "2026-01-15"
},
{
"RequestId": "a1b2c3d4-0001-0000-0000-000000000002",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"SalesOrderId": "SO-000124",
"PostingDate": "2026-01-15"
}
]
}

Response Format -- MGCLatticeBulkOperationResponseContract​

{
"Success": false,
"Status": 6,
"Message": "1 of 2 item(s) succeeded.",
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"TotalCount": 2,
"SuccessCount": 1,
"FailureCount": 1,
"StartDateTimeUtc": "2026-01-15T10:30:00.000Z",
"EndDateTimeUtc": "2026-01-15T10:30:02.468Z",
"DurationMs": 2468,
"Results": [
{
"ItemIndex": 1,
"Success": true,
"Status": 3,
"ErrorCode": 0,
"IsRetryable": false,
"DocumentId": "SO-000123",
"RequestId": "a1b2c3d4-0001-0000-0000-000000000001",
"Message": "Sales order SO-000123 confirmed with confirmation SO-000123-1.",
"Errors": []
},
{
"ItemIndex": 2,
"Success": false,
"Status": 4,
"ErrorCode": 4,
"IsRetryable": false,
"DocumentId": "SO-000124",
"RequestId": "a1b2c3d4-0001-0000-0000-000000000002",
"Message": "Sales order confirmation failed due to validation or business rule constraints.",
"Errors": ["Insufficient on-hand inventory for item A0001."]
}
]
}
FieldTypeDescription
Successbooleantrue only when every item succeeded
Statusenum MGCLatticeServiceCallStatusOverall outcome: Succeeded (every item succeeded), Failed (every item failed, or the request list was missing or empty) or PartialSuccess (mixed). See MGCLatticeServiceCallStatus.
MessagestringTop-level message: why the request list was refused, otherwise a summary such as 1 of 2 item(s) succeeded.; per-item detail is on each result
CorrelationIdGUIDCorrelation ID for tracing
TotalCountintegerTotal number of items in the batch
SuccessCountintegerNumber of items that succeeded
FailureCountintegerNumber of items that failed
StartDateTimeUtc / EndDateTimeUtcdatetimeWhen the bulk operation started and finished
DurationMsintegerElapsed time of the whole bulk operation in milliseconds
ResultsMGCLatticeBulkItemResultContract[]Per-item results

MGCLatticeBulkItemResultContract:

FieldTypeDescription
ItemIndexintegerOne-based position of the item in the request list
SuccessbooleanWhether this individual item succeeded
Statusenum MGCLatticeServiceCallStatusPer-item lifecycle status (Succeeded or Failed). See MGCLatticeServiceCallStatus.
ErrorCodeenum MGCLatticeServiceErrorCodePer-item machine-readable error classification (None on success). See MGCLatticeServiceErrorCode.
IsRetryablebooleanWhether this individual item may be safely retried
DocumentIdstringDocument ID for this item
PostedDocumentIdstringNumber of the document this item produced (empty when none)
RequestIdGUIDRequest ID for this item
MessagestringResult message
Errorsstring[]Error messages (if failed)

Each item is processed independently -- failure of one item does not roll back or affect other items in the batch. An empty (null) entry in a *Batch request list fails as its own item with ValidationFailed and the message Request item N is empty. Every item in the request list must be a request. The other items still run.


20. Status Query Operations​

Five read-only operations return document status without performing any mutations. These do not use ttsBegin/ttsCommit.

getSalesOrderStatus​

Service: MGCLatticeSalesOrderPostingService Service Group: MGCLatticeAccountsReceivableServiceGroup

FieldJSON KeyTypeRequiredDescription
Document IdDocumentIdstringYesSales order number to query (the contract is MGCLatticeStatusQueryRequestContract)
Document Id keyDocumentIdExternalKeystringNoThe sales order's alternate key in ExternalSystem, used in place of DocumentId.
External SystemExternalSystemstringNoThe external system DocumentIdExternalKey belongs to.
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"DocumentId": "SO-000123"
}
}

getPurchaseOrderStatus​

Service: MGCLatticePurchaseOrderPostingService Service Group: MGCLatticeAccountsPayableServiceGroup

FieldJSON KeyTypeRequiredDescription
Document IdDocumentIdstringYesPurchase order number to query (the contract is MGCLatticeStatusQueryRequestContract)
Document Id keyDocumentIdExternalKeystringNoThe purchase order's alternate key in ExternalSystem, used in place of DocumentId.
External SystemExternalSystemstringNoThe external system DocumentIdExternalKey belongs to.

getProductionOrderStatus​

Service: MGCLatticeProductionOrderPostingService Service Group: MGCLatticeProductionServiceGroup

FieldJSON KeyTypeRequiredDescription
Document IdDocumentIdstringYesProduction order number to query (the contract is MGCLatticeStatusQueryRequestContract)
Document Id keyDocumentIdExternalKeystringNoThe production order's alternate key in ExternalSystem, used in place of DocumentId.
External SystemExternalSystemstringNoThe external system DocumentIdExternalKey belongs to.

getJournalStatus​

Service: MGCLatticeGeneralLedgerJournalService Service Group: MGCLatticeGeneralLedgerServiceGroup

FieldJSON KeyTypeRequiredDescription
Document IdDocumentIdstringYesLedger journal number to query (the contract is MGCLatticeStatusQueryRequestContract)
Document Id keyDocumentIdExternalKeystringNoThe journal's alternate key in ExternalSystem, used in place of DocumentId.
External SystemExternalSystemstringNoThe external system DocumentIdExternalKey belongs to.

getWorkflowStatus​

Service: MGCLatticeWorkflowActionService Service Group: MGCLatticeWorkflowServiceGroup

Request Contract: MGCLatticeStatusQueryRequestContract

FieldJSON KeyTypeRequiredDescription
Document IdDocumentIdstringYes, unless an external key is sentAny of: the workflow correlation id submitToWorkflow returned (e.g. be1322c8-...), the source record's RecId, or the source document's number (a purchase requisition number, resolved as submitToWorkflow resolves DocumentNumber). The newest tracking record wins.
External System / KeyExternalSystem, DocumentIdExternalKeystringNoA purchase requisition's external key in place of DocumentId, as the other status queries accept

Status Query Response -- MGCLatticeStatusQueryResponseContract​

The five status queries return MGCLatticeStatusQueryResponseContract, a contract of its own (not the common MGCLatticeOrderOperationResponseContract):

FieldTypeDescription
SuccessbooleanWhether the query found the document
ErrorCodeenum MGCLatticeServiceErrorCodeWhy a query failed, as on the common response (for example ValidationFailed for a request without DocumentId, DocumentNotFound for an unknown document); None on success
MessagestringResult or error text
Errorsstring[]The error messages of a failed query
CorrelationIdGUIDEchoed from the request
DocumentIdstringThe document that was queried
DocumentTypestringThe kind of document, for example SalesOrder
DocumentStatusstringCurrent status of the document (e.g., Backorder, Delivered, Invoiced)
LastModifiedDateTimeUtcdatetimeWhen the document was last changed (UTC)
StatusDetailsobject[]Additional status context as named values { "Name": ..., "Value": ... } (dates as yyyy-MM-dd, accounts, workflow state). getWorkflowStatus adds one PendingWorkItem_<RecId> entry per pending work item of the instance, whose value is its assignee: the user a work-item action is taken as (ActingUserId), and for a Faulted instance (which creates no work item) a FaultMessage entry with the fault text the workflow history shows
{
"Success": true,
"ErrorCode": 0,
"Message": "Status retrieved for sales order SO-000123.",
"Errors": [],
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"DocumentId": "SO-000123",
"DocumentType": "SalesOrder",
"DocumentStatus": "Invoiced",
"LastModifiedDateTimeUtc": "2026-01-15T10:30:01Z",
"StatusDetails": [
{ "Name": "SalesStatus", "Value": "Invoiced" },
{ "Name": "CustAccount", "Value": "US-001" },
{ "Name": "ConfirmDate", "Value": "2026-01-10" },
{ "Name": "PackingSlipDate", "Value": "2026-01-12" },
{ "Name": "InvoiceDate", "Value": "2026-01-15" }
]
}

21. Async Operations​

Service: MGCLatticeAsyncOperationService Service Group: MGCLatticeAsyncOperationServiceGroup

Long-running operations can be queued to the D365 batch framework for asynchronous execution. The pattern is submit-then-poll.

submitAsyncOperation​

Validates the request, creates a tracking record in MGCLatticeAsyncOperationTracking and schedules a one-time runtime batch job that runs the operation, in one transaction, and returns a tracking ID. A submission that reports failure therefore leaves no queued operation behind. The runtime job moves to the batch history when it ends and is removed by the batch history cleanup.

Idempotent submission. The submission's RequestId is required and is its idempotency key (unique on the tracking table). Repeating a submission with the same RequestId for the same service operation returns the first submission's TrackingId and current Status with Success true and queues nothing again; the same RequestId for another service operation is refused with ErrorCode DuplicateRequest. The posting itself is deduplicated by the RequestId inside the payload (see the payload rules below).

Access to the target operation. Submitting requires access to the target service operation as well as to submitAsyncOperation (privilege MGCLatticeAsyncOperationServiceMaintain): the same privilege that is needed to call the target directly. Without it the submission is refused with You do not have access to the service operation <ServiceName>.<OperationName>, so it cannot be submitted for async execution. .... Before the operation runs, the processor checks again that the user who submitted it (the tracking record's creator) still has that access; if not, or if no submitter is recorded, the operation is set to Failed and parked in the dead-letter queue. Replaying it from the dead-letter queue requires the replaying user (or the owner of the dead-letter retry batch job) to have access to the target operation.

Target operationsPrivilege that grants them
MGCLatticeFixedAssetService runDepreciationProposal, postAcquisition, postAssetTransactionMGCLatticeFixedAssetsServiceMaintain
MGCLatticeFixedAssetService postDisposalMGCLatticeFixedAssetsDisposalMaintain
MGCLatticeJournalPostingService (all five)MGCLatticeJournalPostingMaintain; the journal's own operations are checked when it posts (see 8a)
MGCLatticeInventoryCostService activatePendingPricesMGCLatticeInventoryCostActivateMaintain
MGCLatticeInventoryCostService calculateItemCostsMGCLatticeInventoryCostCalculateMaintain
MGCLatticeCurrencyRevaluationService (all three), MGCLatticeGeneralLedgerJournalService postGeneralJournal, MGCLatticeBudgetRegisterService (both)MGCLatticeGeneralLedgerServiceMaintain
MGCLatticeGeneralLedgerJournalService postIntercompanyJournalMGCLatticeGeneralLedgerIntercompanyMaintain
MGCLatticeGeneralLedgerJournalService reverseJournalMGCLatticeGeneralLedgerJournalReverseMaintain

Request payload. The payload must be readable as the operation's request contract and carry its own RequestId (the posting's idempotency key) and an existing LegalEntityId, which the operation requires when it runs; otherwise the submission is refused with ValidationFailed and nothing is queued. A payload that cannot be read is refused with The request payload for <ServiceName>.<OperationName> cannot be read as the operation's request contract. Correct the payload and submit it again.; a payload without RequestId with The request payload for <ServiceName>.<OperationName> has no RequestId. ....

Request Contract: MGCLatticeAsyncOperationRequestContract

FieldJSON KeyTypeRequiredDescription
Correlation IDCorrelationIdstring (GUID)NoStored on the tracking record and echoed in the response
Request IDRequestIdstring (GUID)YesThe submission's idempotency key: a repeat returns the first submission's tracking ID
Legal EntityLegalEntityIdstringNoRecorded on the tracking record; defaults to the payload's LegalEntityId
User ContextUserContextstringNoInformational; recorded on the tracking record. The submitting user is the record's SubmittedBy
Service NameServiceNamestringYesThe Lattice service that owns the operation (see supported operations below)
Operation NameOperationNamestringYesThe service operation to run
Request PayloadRequestPayloadstringYesThe operation's own request, serialized to a JSON string: the object you would send as _request when calling the operation directly

Supported operations. Submission accepts only the service and operation pairs that are registered and enabled in the async operation registry (MGCLatticeAsyncOperationRegistry). The pairs are product-owned: each one needs handler code, so the product seeds them and customers cannot add or delete one. An administrator can disable a seeded pair on System administration > Setup > Lattice > Async operation registry (Enabled is the only editable column). What callers see:

  • Unregistered pair: refused with ValidationFailed: The operation <ServiceName>.<OperationName> is not supported for async execution.
  • Disabled pair: refused with OperationDisabled: The operation <ServiceName>.<OperationName> is disabled for async execution by an administrator. Submit it synchronously, or ask an administrator to enable it in the async operation registry. Call the operation synchronously instead, or ask for it to be enabled.
  • Pair disabled after the item was queued: the queued item is not run. getAsyncOperationStatus returns Status 4 (Failed) and ErrorCode OperationDisabled, with Message and Errors The operation <ServiceName>.<OperationName> was not run because an administrator disabled it for async execution after it was queued. ..., and the item is parked in the dead-letter queue (non-retryable, error code OperationDisabled) so an operator can replay it after the pair is enabled again.

Both refusals are reported the same way as a missing field (see the response below): nothing is queued. The handler class and the request-contract class of each pair are resolved in the product code, not stored in the registry, so a later release that changes them needs no data fix. Re-seeding the registry (it seeds itself on first use and tops up pairs added by a later release) only inserts missing pairs, so it never re-enables a pair an administrator disabled. The registry is seeded with these nineteen, all enabled:

ServiceNameOperationNameRequest payload contract
MGCLatticeFixedAssetServicerunDepreciationProposalMGCLatticeFixedAssetDepreciationRequestContract
MGCLatticeFixedAssetServicepostAcquisitionMGCLatticeFixedAssetAcquisitionRequestContract
MGCLatticeFixedAssetServicepostDisposalMGCLatticeFixedAssetDisposalRequestContract
MGCLatticeFixedAssetServicepostAssetTransactionMGCLatticeFixedAssetTransactionRequestContract
MGCLatticeCurrencyRevaluationServicerunCustomerRevaluation, runVendorRevaluation, runLedgerRevaluationMGCLatticeCurrencyRevaluationRequestContract
MGCLatticeInventoryCostServiceactivatePendingPricesMGCLatticePendingPriceActivationRequestContract
MGCLatticeInventoryCostServicecalculateItemCostsMGCLatticeItemCostCalculationRequestContract
MGCLatticeGeneralLedgerJournalServicepostGeneralJournal, postIntercompanyJournalMGCLatticeGeneralJournalPostRequestContract
MGCLatticeGeneralLedgerJournalServicereverseJournalMGCLatticeJournalReversalRequestContract
MGCLatticeJournalPostingServicepostLedgerJournalMGCLatticeLedgerJournalPostingRequestContract
MGCLatticeJournalPostingServicepostInventoryJournal, postProjectJournal, postProductionJournalMGCLatticeJournalPostingRequestContract
MGCLatticeJournalPostingServicepostTradeAgreementJournalMGCLatticeTradeAgreementJournalPostingRequestContract
MGCLatticeBudgetRegisterServicepostBudgetEntry, postBudgetTransferMGCLatticeBudgetEntryPostRequestContract

This example queues the general journal post shown in section 8:

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"ServiceName": "MGCLatticeGeneralLedgerJournalService",
"OperationName": "postGeneralJournal",
"RequestPayload": "{\"RequestId\":\"5143fdcf-9a1e-4b6c-8a0e-2f6d7c1b9e42\",\"LegalEntityId\":\"USMF\",\"JournalNameId\":\"GenJrn\",\"Description\":\"Monthly accrual entries\",\"PostingDate\":\"2026-01-31\",\"Lines\":[{\"MainAccountId\":\"600100\",\"AmountCurDebit\":10000.00,\"CurrencyCode\":\"USD\",\"Description\":\"Accrued expenses\"},{\"MainAccountId\":\"200100\",\"AmountCurCredit\":10000.00,\"CurrencyCode\":\"USD\",\"Description\":\"Accrued expenses - offset\"}]}"
}
}

Response Contract: MGCLatticeAsyncOperationResponseContract (not the common MGCLatticeOrderOperationResponseContract)

{
"Success": true,
"TrackingId": "e4f5a6b7-c8d9-0123-4567-89abcdef0123",
"Status": 1,
"ErrorCode": 0,
"IsRetryable": false,
"Message": "Operation queued for async processing. Use the tracking ID to check its status.",
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Status is 1 (Queued) when the operation was accepted, or the current status of the first submission for a repeated RequestId. A refused submission returns Success false, Status 4 (Failed), an all-zero TrackingId, the reason in Message and its ErrorCode: ValidationFailed (a missing field, an unregistered pair, a payload that cannot run), OperationDisabled, AccessDenied (no access to the target operation), DuplicateRequest (the RequestId was used for another operation) or LicenseNotValid (IsRetryable true). No tracking record or batch job is created.

Failures after submission. An operation that fails while it runs is set to Failed and dead-lettered (see 32. Integration Dead-Letter Queue). When the target operation answers with a failure, the item is dead-lettered as retryable (Retrying) and retried automatically only when that response has IsRetryable true; any other failed response (for example ValidationFailed or BusinessRule) is Parked for an operator to fix and replay. An exception that escapes the target operation while it runs is dead-lettered as retryable (TransientRuntime). A failure that cannot succeed on a retry is parked as non-retryable, for an operator to fix and replay: no handler for the operation, a payload that cannot be read or an operation the handler does not implement (ValidationFailed), a submitter without access to the target operation (AccessDenied), or a pair disabled after it was queued (OperationDisabled). An exception raised by these pre-run checks themselves also closes the operation as Failed, so a claimed operation does not stay Processing.

getAsyncOperationStatus​

Reads the status of a previously submitted operation from the MGCLatticeAsyncOperationTracking table.

Request Contract: MGCLatticeAsyncOperationStatusRequestContract

FieldJSON KeyTypeRequiredDescription
Correlation IDCorrelationIdstring (GUID)NoEchoed when the query is refused
Tracking IDTrackingIdstring (GUID)YesThe tracking ID returned by submitAsyncOperation
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"TrackingId": "e4f5a6b7-c8d9-0123-4567-89abcdef0123"
}
}

Response Contract: MGCLatticeAsyncOperationStatusContract - this operation does not return the common MGCLatticeOrderOperationResponseContract. Success is the outcome of the query (the operation was found); Status is the state of the operation.

FieldJSON KeyTypeDescription
SuccessSuccessbooleantrue when the tracking ID was valid and the operation was found
Tracking IDTrackingIdstring (GUID)The tracking record's id (all zeros when the request was refused before lookup)
StatusStatusMGCLatticeAsyncOperationStatusEmitted as the enum's integer value: 0 None (refused query), 1 Queued, 2 Processing, 3 Succeeded, 4 Failed, 7 NotFound
Error CodeErrorCodeMGCLatticeServiceErrorCodeFor a Failed operation, the code of its failure; for a refused query ValidationFailed; for an unknown tracking ID DocumentNotFound; otherwise None
Is RetryableIsRetryablebooleantrue when the failure was a transient runtime fault
MessageMessagestringThe inner operation's message once terminal; otherwise empty, or the reason the query was refused
ErrorsErrorsstring[]The inner operation's error messages once Failed, or the reason the query was refused
Document IDDocumentIdstringThe inner operation's document id once Succeeded
Posted Document IDPostedDocumentIdstringThe number of the document the inner operation produced (for a GL post, the posted journal number) once Succeeded
SubmittedSubmittedDateTimeUtcdatetimeWhen the tracking record was created
CompletedCompletedDateTimeUtcdatetime1900-01-01T00:00:00Z until the operation is terminal
Correlation IDCorrelationIdstring (GUID)Echoed from the submit request

Response (in progress):

{
"Success": true,
"TrackingId": "e4f5a6b7-c8d9-0123-4567-89abcdef0123",
"Status": 2,
"ErrorCode": 0,
"IsRetryable": false,
"Message": "",
"Errors": [],
"DocumentId": "",
"PostedDocumentId": "",
"SubmittedDateTimeUtc": "2026-09-18T02:38:27Z",
"CompletedDateTimeUtc": "1900-01-01T00:00:00Z",
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Response (completed):

{
"Success": true,
"TrackingId": "e4f5a6b7-c8d9-0123-4567-89abcdef0123",
"Status": 3,
"ErrorCode": 0,
"IsRetryable": false,
"Message": "General journal 00045 posted successfully.",
"Errors": [],
"DocumentId": "00045",
"PostedDocumentId": "00045",
"SubmittedDateTimeUtc": "2026-09-18T02:38:27Z",
"CompletedDateTimeUtc": "2026-09-18T02:38:29Z",
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

An unknown tracking ID returns Success false, Status 7 (NotFound), ErrorCode DocumentNotFound and No async operation found with tracking ID ...; a request without TrackingId returns Success false, Status 0 (None), ErrorCode ValidationFailed and TrackingId is required.

Replayed collections. The batch task rehydrates RequestPayload with FormJsonSerializer::deserializeObject, which fills a List data member only when the member declares DataCollectionAttribute (AifCollectionTypeAttribute alone serves the synchronous custom-service path). Every Lattice contract list member declares both, so a queued request keeps its lines when the batch task runs it.

The submitAsyncOperation operation returns MGCLatticeAsyncOperationResponseContract and getAsyncOperationStatus returns MGCLatticeAsyncOperationStatusContract. On both contracts the Status member is the MGCLatticeAsyncOperationStatus enum (not a free-form string), and the JSON carries its integer value: 0 None, 1 Queued, 2 Processing, 3 Succeeded, 4 Failed, 7 NotFound.

Tracking statuses (MGCLatticeAsyncOperationStatus): None, Queued, Processing, Succeeded, Failed, NotFound. See MGCLatticeAsyncOperationStatus.


22. Financial Dimension Support​

General journal lines (used by postGeneralJournal and postIntercompanyJournal) accept an optional Dimensions array for specifying financial dimension values on each line. Dimensions are resolved server-side via DimensionAttributeValueSetStorage and LedgerDimensionFacade.

Dimension Value Contract -- MGCLatticeDimensionValueContract​

FieldJSON KeyTypeRequiredDescription
Dimension NameDimensionNamestringYesFinancial dimension name (e.g., Department, CostCenter)
Dimension ValueDimensionValuestringYesDimension value code (e.g., 022, 007)

Example -- General Journal with Dimensions​

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "GenJrn",
"Description": "Monthly accrual with dimensions",
"PostingDate": "2026-01-31",
"Lines": [
{
"MainAccountId": "600100",
"AmountCurDebit": 10000.00,
"CurrencyCode": "USD",
"Description": "Training expenses - Engineering",
"Dimensions": [
{ "DimensionName": "Department", "DimensionValue": "022" },
{ "DimensionName": "CostCenter", "DimensionValue": "007" },
{ "DimensionName": "Purpose", "DimensionValue": "Training" }
]
},
{
"MainAccountId": "200100",
"AmountCurCredit": 10000.00,
"CurrencyCode": "USD",
"Description": "Training accrual offset",
"Dimensions": [
{ "DimensionName": "Department", "DimensionValue": "022" }
]
}
]
}
}

Intercompany Journal with OffsetCompany​

The postIntercompanyJournal operation supports cross-company offset account resolution. Each line can specify an OffsetCompany field to indicate the legal entity for the offset account:

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"UserContext": "Admin",
"JournalNameId": "IntJrn",
"Description": "Intercompany allocation",
"PostingDate": "2026-01-31",
"Lines": [
{
"MainAccountId": "600100",
"OffsetMainAccountId": "200100",
"OffsetCompany": "DEMF",
"AmountCurDebit": 25000.00,
"CurrencyCode": "USD",
"Description": "Shared services allocation to DEMF"
}
]
}
}

Source (Origin) Attribution - automatic financial-dimension stamping​

Separately from line-level dimensions on journal requests, inbound sales orders can be stamped with a financial dimension derived from their source/origin so that downstream ledger postings are attributable to the channel that created the order. This is a configuration-driven, self-contained capability (no line-level input required).

ArtifactTypePurpose
MGCLatticeSalesOriginDimensionParametersTable (one row per legal entity)Master switch StampingEnabled (default Off - inert until configured), set with the Sales-origin dimension stamping enabled check box on the mapping page, which creates the legal entity's row when the page opens
MGCLatticeSalesOriginDimensionMapTable + grid form (also holds the stamping switch)Maps a SalesTable.SalesOriginId value to a target dimension name + value (unique per origin)
MGCLatticeSalesOriginDimensionStamperClassMerges the mapped dimension value into the order's DefaultDimension using the standard DimensionAttributeValueSetStorage merge idiom
MGCLatticeSalesOriginDimension_SalesTable_EventHandlerData event handlerOn DataEventType::Inserting, stamps DefaultDimension before the physical write

When enabled, each inserted sales order whose SalesOriginId is mapped has the mapped dimension merged into its default dimension. An unmapped origin or an unresolved dimension value is a silent no-op that preserves the existing DefaultDimension.


23. Process Automation​

The Lattice model registers with the D365 Process Automation Framework to automatically process queued async operations. This is a background polled process -- no manual intervention is required.

How It Works​

  1. The Process Automation Framework polls on a configurable interval (default: 60 seconds).
  2. MGCLatticeAsyncOperationProcessAutomationTask queries the MGCLatticeAsyncOperationTracking table for records with Status = Queued.
  3. For each queued record, it creates an MGCLatticeAsyncOperationProcessor instance.
  4. The processor deserializes the stored request payload, dispatches to the appropriate service, and records the result back to the tracking record.

submitAsyncOperation also schedules a batch job of its own for every submission, so most operations start within seconds and the polled task is the fallback. When both reach the same operation, only the processor that moves the record out of Queued, under a row lock, runs it. The other finds the record already Processing and leaves it alone.

Stale Processing recovery. Each run of the process automation task, and each run of the Lattice dead-letter retry background process (MGCLatticeIntegrationDlqRetryBatch), first recovers operations that have been Processing for more than 60 minutes without a result (the AOS or batch task stopped after claiming them); an operation whose batch job is still running is left alone. It reads the idempotency claim of the request inside the payload and never runs an operation whose effect may have committed:

  • The inner request's claim shows it succeeded: the operation is marked Succeeded with that document, and its message says the result was recovered from the idempotency log.
  • There is no claim (the operation never started posting, or it failed and released its claim): it is queued again under the same RequestId, once. The process automation task dispatches it (a queued operation is dispatched only by the process automation task or by the batch job of its submission).
  • The claim is still Processing and less than 60 minutes old: the operation is still running and is left alone.
  • Otherwise (no inner RequestId, a claim Processing for more than 60 minutes, or no claim when the operation was already queued again once): it is set to Failed and parked in the dead-letter queue for manual review with error code RequestNeedsReview. Check the target documents before replaying it.

Supported Operations for Async Processing​

ServiceOperations
MGCLatticeFixedAssetServicerunDepreciationProposal, postAcquisition, postDisposal, postAssetTransaction
MGCLatticeCurrencyRevaluationServicerunCustomerRevaluation, runVendorRevaluation, runLedgerRevaluation
MGCLatticeInventoryCostServiceactivatePendingPrices, calculateItemCosts
MGCLatticeGeneralLedgerJournalServicepostGeneralJournal, postIntercompanyJournal, reverseJournal
MGCLatticeJournalPostingServicepostLedgerJournal, postInventoryJournal, postProjectJournal, postProductionJournal, postTradeAgreementJournal
MGCLatticeBudgetRegisterServicepostBudgetEntry, postBudgetTransfer

Configuration​

Navigate to System Administration > Setup > Process automations to view and configure the polling schedule. The async operation task is the Lattice Async Operation Processing background process (every minute) on the Background processes tab. You can adjust the polling interval, switch the process off or on, and view execution history from this page. Process automation must be initialized in the environment and Lattice Async Operation Processing left on: it re-dispatches operations that the stale Processing recovery queued again. The Lattice dead-letter retry background process also runs the stale Processing recovery, so stuck operations are closed even where Lattice Async Operation Processing is switched off.

Lattice maintenance background processes​

Eight maintenance jobs run as polled background processes of the same framework, so a deployment schedules them and no batch job has to be created. The framework registers their types and series on every database synchronization (through its SysSetup hook); the processes are listed on the Background processes tab of System Administration > Setup > Process automations, where an administrator can change an interval, set a sleep window or switch a process off.

Background process (type name)PolledCreates a batch job
Lattice dead-letter retry (MGCLatticeIntegrationDlqRetryBatch)Every 5 minutesWhen a Retrying dead letter is due or a Requeued one exists (hasDueWork)
Lattice idempotency reconciliation (MGCLatticeIdempotencyReconciliationSweep)HourlyWhen a self-describing claim has been Processing for over 60 minutes (hasCandidates)
Lattice business event reconciliation (MGCLatticeBusinessEventReconciliationSweep)HourlyWhen a failed, unreconciled event with retries left is at least 15 minutes old (hasCandidates)
Lattice workflow stalled or failed alerts (MGCLatticeWorkflowStalledAlertBatch)HourlyEvery poll
Lattice service call statistics rollup (MGCLatticeServiceCallStatisticsRollup)DailyEvery poll
Lattice integration log cleanup (MGCLatticeServiceLogCleanup)DailyEvery poll
Lattice file ingestion cleanup (MGCLatticeFileIngestCleanup)DailyEvery poll
Lattice sales price effectivity events (MGCLatticeTradeAgreementPriceEffectivityBatch)DailyEvery poll
ArtifactTypePurpose
MGCLatticeMaintenanceAutomationClassThe definitions: type names, labels, polling patterns, the work check (hasWork, workList) and newJob / runJob
MGCLattice*AutomationTypeRegistration, MGCLattice*AutomationSeriesRegistrationClasses (16)One type and one series registration per process (ProcessScheduleITypeRegistration, ProcessScheduleISeriesRegistration), delegating to MGCLatticeMaintenanceAutomation
MGCLatticeMaintenanceAutomationTaskClass (ProcessAutomationTask)The one task of all eight types; returns the work of the type it was polled for
MGCLatticeMaintenanceAutomationControllerClass (SysOperationServiceController)The batch task; its data contract is the polled ProcessScheduleWorkItem
MGCLatticeMaintenanceAutomationServiceClassrunTask runs the job and records the result (and on failure the infolog messages) in the process automation results without failing the batch task

The framework runs only SysOperationServiceController work items and takes no parameters for a background process, so each RunBaseBatch job runs inside the controller's task with the defaults its constructor sets (the values its dialog proposes). Each process runs as its series owner, by default the user the database synchronization ran as. Do not also schedule these jobs as recurring batch jobs; to run one on another schedule or with other values, switch its background process off and schedule the job from its menu item.

Recurring data job health alerts. One more background process of the same framework, Lattice recurring data job health alerts (type name MGCLatticeRecurringJobHealthAlerts), is polled every 15 minutes and creates a batch job when a recurring data job or a health row exists. Each run evaluates the health of every recurring data job, stores it on the job's row of LatticeRecurringJobHealths and raises the Recurring data job health changed business event for each job with alerts on whose health state changed; see 37. Recurring Data Job Health Entities. It is not one of the maintenance jobs and has no menu item: the Refresh and RefreshAll actions of the health entity, and the recurring integration health page, evaluate on demand and raise the same events. Change its interval or switch it off on the Background processes tab like the others.

Tracking Status Lifecycle​

Queued --> Processing --> Succeeded
\-> Failed

A record enters Queued status when submitted via submitAsyncOperation. The processor that claims it (the submission's own batch job or the process automation task) transitions it to Processing, and then to Succeeded or Failed upon completion; a record that has left Queued is dispatched again only when the stale Processing recovery above queues it again. A successful dead-letter replay sets a Failed record to Succeeded with the posted document. Use getAsyncOperationStatus (see 21. Async Operations) to poll for the final state.

Log Retention - MGCLatticeServiceLogCleanup​

MGCLatticeServiceLogCleanup is a RunBaseBatch retention job that bounds the high-churn log tables. Each run performs a set-based, independently-guarded delete_from per table (one table failing does not stop the others) and reports per-table deleted counts to the infolog. It runs daily as the Lattice integration log cleanup background process of the process automation framework, with the default retention windows; run it interactively (menu item MGCLatticeServiceLogCleanup, privilege MGCLatticeServiceLogMaintenance) for other values. See Lattice maintenance background processes.

TableAged byDefault retentionNotes
MGCLatticeServiceCallLogStartDateTimeUtc90 daysEvery call writes a row, including calls answered without executing (cached replay, in progress, needs review, RequestId conflict, license refusal). An operation's own retention days on its logging configuration override the default
MGCLatticeServiceCallStatisticsStatisticsDate90 days (call log window)Daily rollups
MGCLatticeFileIngestLogsystem createdDateTime90 daysDiagnostic ingestion log
MGCLatticeServiceIdempotencyLogCompletedDateTimeUtc30 daysOnly Succeeded rows are purged; in-flight (Processing) claims are never deleted, so duplicate suppression is never undermined. Close stale claims with Mark succeeded or Release claim
MGCLatticeAsyncOperationTrackingSubmittedDateTimeUtc30 daysSucceeded and Failed rows only
MGCLatticeIntegrationDeadLetterLastAttemptDateTimeUtc90 daysReprocessed and Discarded rows only; open (Retrying, Parked, Held) and Requeued rows are kept
MGCLatticeBusinessEventLogsystem createdDateTime90 daysSuccess rows and failed rows the replay sweep has finished with; a failed row still waiting for a replay is kept whatever its age. Dialog field Business event log (days)

The metadata-refresh logs (MGCLatticeServiceMetadataRefreshLog, MGCLatticeODataRefreshLog) are purged by creation date, with the Service metadata refresh log (days) and OData refresh log (days) values of the job dialog.

Idempotency Reconciliation Sweep - MGCLatticeIdempotencyReconciliationSweep​

MGCLatticeIdempotencyReconciliationSweep is a RunBaseBatch job that resolves stale Processing idempotency claims - claim rows left behind when a create-then-post worker crashed after creating a document but before recording completion. It is the automated counterpart to the claim-first idempotency described under Duplicate RequestId.

It relies on the self-describing columns that create-then-post operations stamp on MGCLatticeServiceIdempotencyLog inside the create transaction - LegalEntityId, DocumentTable, and DocumentId - so a stale claim names the exact document it created. The sweep runs in two phases: (1) snapshot the stale Processing claims; (2) per claim, dispatch to a document reconcile handler selected by DocumentTable (MGCLatticeIdempotencyReconcileHandlerLedgerJournal / …ProjJournal / …InventJournal, via a factory) that probes whether the named document exists and was posted. The outcome is stamped on the claim's ReconcileState field.

EnumMembers (numeric)Role
MGCLatticeDocReconcileOutcomeNotFound (0), CreatedNotPosted (1), Posted (2)Result of a handler probing for the created document
MGCLatticeIdempotencyReconcileStateNotReconciled (0), ResolvedSucceeded (1), ReleasedForRetry (2), ManualRequired (3)Disposition stamped on the claim by the sweep

Mapping: Posted → finalize the claim to Succeeded (ResolvedSucceeded); NotFound → delete/release the claim so the request can be safely retried (ReleasedForRetry); CreatedNotPosted → park for manual review (ManualRequired). A claim already parked as ManualRequired is not probed again. Runs interactively (menu item) or on a batch schedule; see the idempotency reconciliation runbook.

Operator actions. A parked claim, or a stale claim that names no document, is closed by an operator on Service idempotency log with Mark succeeded (the original request's document exists and is posted: the claim becomes Succeeded with ReconcileState ResolvedSucceeded, so a repeat replays it) or Release claim (the request committed nothing: the claim is deleted, so the caller can send the same RequestId again). Both act only on a Processing claim, ask for confirmation, and require the MGCLatticeIntegrationOpsManagePrivilege privilege (action menu items MGCLatticeIdempotencyClaimMarkSucceeded and MGCLatticeIdempotencyClaimRelease).


24. OData Monitoring Entities​

Four read-only OData entities (plus the dead-letter entity described in 32. Integration Dead-Letter Queue) expose operational data for external monitoring, reporting, and integration diagnostics. They are published in the Lattice model, shared across legal entities, and available through OData only (they are not enabled for Data management).

EntityCollection NameBacking TableDescription
MGCLatticeServiceCallLogEntityLatticeServiceCallLogsMGCLatticeServiceCallLogOne row per logged service call, including calls answered without executing (a cached replay, an in-progress or needs-review answer, a RequestId conflict, a license refusal): ServiceName, OperationName, LegalEntityId, UserContext (the caller's informational request member, blank when not sent), CalledBy (the authenticated user the call ran as), StartDateTimeUtc, EndDateTimeUtc, millisecond-precision DurationMs, Success, Status, Message (the outcome summary), ErrorDetails (the response's Errors, separated by ; and shortened to 1,000 characters; empty when there were none), DocumentId, PostedDocumentId, the RequestId, CorrelationId, and ExecutionId, the machine-readable ErrorCode (MGCLatticeServiceErrorCode; None on success), and IsPreview (Yes for a posting-preview run-and-abort call, whose changes were rolled back). Which calls are logged follows each operation's logging level: every call by default (All), failures only (ErrorsOnly), or none (Off).
MGCLatticeServiceCallStatisticsEntityLatticeServiceCallStatisticsMGCLatticeServiceCallStatisticsDaily per-operation rollups of the call log: CallCount, SuccessCount, FailureCount, TotalDurationMs, MinDurationMs, MaxDurationMs, AvgDurationMs, and LastCallDateTimeUtc per ServiceName, OperationName, and UTC StatisticsDate. Filled by the service call statistics rollup batch job from the rows the call log kept; each run rebuilds whole UTC days, starting at midnight of the first day of its window.
MGCLatticeServiceIdempotencyLogEntityLatticeServiceIdempotencyLogsMGCLatticeServiceIdempotencyLogClaim-first idempotency tracking, one row per claimed RequestId: CorrelationId, ServiceName, OperationName, Success, DocumentId, PostedDocumentId (replayed on a repeat), CompletedDateTimeUtc, the claim Status (MGCLatticeServiceCallStatus: Processing while the claim is in flight, Succeeded once finalized) and ClaimedDateTimeUtc, the LegalEntityId and DocumentTable of the document created inside the claim, and ReconcileState (MGCLatticeIdempotencyReconcileState), the disposition applied by the reconciliation sweep. A claim row is inserted before execution; on success it is finalized (Success = Yes with a completion time), and on failure it is deleted so the request can be retried with the same RequestId. A row with no completion time is a claim that has not finished. Long-lived rows are therefore the succeeded claims that back duplicate replay. To find stale claims, filter on Status Processing with an old ClaimedDateTimeUtc.
MGCLatticeAsyncOperationTrackingEntityLatticeAsyncOperationTrackingRecordsMGCLatticeAsyncOperationTrackingOne row per operation submitted through the asynchronous operation service: TrackingId, RequestId, CorrelationId, ServiceName, OperationName, LegalEntityId, UserContext (informational), SubmittedBy (the user who submitted it), Status, SubmittedDateTimeUtc, CompletedDateTimeUtc, the resulting DocumentId and PostedDocumentId, Message, the failure's ErrorCode and ErrorDetails, the RequestPayload, and the BatchJobId. RequestId is unique (the submission's idempotency key).

In $metadata the four entity types are named LatticeServiceCallLog, LatticeServiceCallStatistic, LatticeServiceIdempotencyLog and LatticeAsyncOperationTracking (for example Microsoft.Dynamics.DataEntities.LatticeServiceCallLog), like every other public Lattice entity.

OperationName in the call log, the call statistics and the idempotency log (and in service telemetry) is the public operation name, for example postBudgetEntry / postBudgetTransfer, postCustomerPaymentJournal / postVendorPaymentJournal and postInvoiceRegisterJournal / postInvoiceApprovalJournal.

Access Pattern​

GET {baseUrl}/data/{CollectionName}

All four entities support standard OData query options: $filter, $select, $top, $skip, and $orderby. RequestId, CorrelationId, ExecutionId, and TrackingId are GUIDs (Edm.Guid), so filter on them with an unquoted value.

Status is an enum. The Status property on MGCLatticeServiceCallLogEntity and MGCLatticeServiceIdempotencyLogEntity (MGCLatticeServiceCallStatus) and on MGCLatticeAsyncOperationTrackingEntity (MGCLatticeAsyncOperationStatus) is exposed as an enumeration type in $metadata, not a string. Filter against it using the qualified enum-member syntax - Status eq Microsoft.Dynamics.DataEntities.MGCLatticeServiceCallStatus'Failed' - and the property serializes as the member name (e.g. "Status": "Failed") in responses. See MGCLatticeServiceCallStatus and MGCLatticeAsyncOperationStatus for the full member lists. The same applies to ErrorCode (MGCLatticeServiceErrorCode), ReconcileState (MGCLatticeIdempotencyReconcileState), and the NoYes flags Success and IsPreview, which serialize as "Yes" or "No" and are filtered as IsPreview eq Microsoft.Dynamics.DataEntities.NoYes'Yes'.

Example Queries​

Retrieve recent failed service calls:

GET {baseUrl}/data/LatticeServiceCallLogs?$filter=Status eq Microsoft.Dynamics.DataEntities.MGCLatticeServiceCallStatus'Failed'&$orderby=StartDateTimeUtc desc&$top=50

Check idempotency status for a specific RequestId:

GET {baseUrl}/data/LatticeServiceIdempotencyLogs?$filter=RequestId eq 7c9e6679-7425-40de-944b-e07fc1f90ae7

List all async operations currently in progress:

GET {baseUrl}/data/LatticeAsyncOperationTrackingRecords?$filter=Status eq Microsoft.Dynamics.DataEntities.MGCLatticeAsyncOperationStatus'Processing'&$select=TrackingId,ServiceName,OperationName,Status,SubmittedDateTimeUtc

Get async operation results for a date range:

GET {baseUrl}/data/LatticeAsyncOperationTrackingRecords?$filter=SubmittedDateTimeUtc ge 2026-01-01T00:00:00Z and SubmittedDateTimeUtc le 2026-01-31T23:59:59Z&$orderby=SubmittedDateTimeUtc desc

These entities are read-only. Insert, update, and delete operations are not supported through OData.


25. File Ingestion Framework​

A pull-based, high-volume file integration framework that connects to cloud storage, pulls data files on a schedule, claim-checks each file into D365 Document Management, decomposes it into per-record segments, transforms each record with a Liquid template, and dispatches the result to a target in-F&O service. Work is broken into small, independently-retryable units so many batch threads can drain the staging table in parallel. See the file ingestion user guide for how to set it up.

This framework is configured and operated from F&O forms and batch jobs (not exposed as a SOAP/REST custom service). The artifacts below document the X++ data model, processing classes, security, and the supporting C# interop library.

25.1 Enums​

MGCLatticeFileIngestState - lifecycle state of a segment.

ValueNumericDescription
None0Unset / default
Queued1Staged, awaiting processing (a worker claims it under a row lock; there is no in-progress state)
Processed3Successfully transformed and dispatched
Failed4Exceeded the retry cap
Held6Held by an operator on the bundle inquiry; the segment processor skips it until it is released back to Queued

MGCLatticeFileIngestStorageType - cloud source type.

ValueNumericDescription
Blob0Azure Blob storage
FileShare1Azure File share
Sftp2SFTP server

MGCLatticeFileIngestFileFormat - inbound file format / parser selector.

ValueNumericDescription
Xml0XML; records identified by an element name or element path; each record is converted to JSON before the Liquid transform
Json1JSON; records identified by a JSON path
Csv2CSV / delimited; each row is a record. Delimiter, header, and quote behavior come from the connection; rows are normalized to JSON before the Liquid transform. Delimited only; fixed-width files use FixedWidth.
FixedWidth3Fixed-width text; each non-blank line is a record, normalized to JSON with the connection's FixedWidthColumnSpec

MGCLatticeLogLevel - severity of an MGCLatticeFileIngestLog entry (Info, Warning, Error; shared by all three log tables, see Log Level Enum).

MGCLatticeFileIngestSecretStorage - how a connection stores its secret; shown read-only as Secret storage on the connection page.

ValueNumericDescription
None0Not set: no secret is stored
Encrypted1AuthSecret holds the secret, encrypted with the platform encryption service
KeyVaultReference2AuthSecretKvRef holds an Azure Key Vault secret URI

25.2 Tables​

MGCLatticeFileIngestConnection​

Setup table. One record per configured source. Primary key ConnectionId; alternate-key index ConnectionIdx (ConnectionId). SaveDataPerCompany=No. Delete actions: Restricted to MGCLatticeFileIngestBundle (a connection with bundles cannot be deleted), Cascade to MGCLatticeFileIngestConnectionLock, MGCLatticeFileIngestSizeObservation and MGCLatticeFileIngestProcessedFile. The bundle, log, lock, size-observation and processed-file tables relate to it on ConnectionId. The pull jobs never update this record.

FieldTypeDescription
ConnectionIdstring(60)Unique connection identifier (mandatory, PK)
Namestring(100)Friendly description
StorageTypeenum MGCLatticeFileIngestStorageTypeSource storage type
Endpointstring(255)Storage endpoint / host (may also be supplied in the secret JSON)
ContainerOrSharestring(255)Blob container or file-share name; for SFTP the remote root path that relative paths are resolved under (blank: the login directory)
FolderPathstring(255)Sub-path within the container/share/SFTP root to scan; for SFTP a path that starts with / is used as is
FilePatternstring(100)Filename wildcard filter (e.g. *.xml)
AuthSecretcontainer (EDT EncryptedField)The connection secret as JSON (connection string / SAS / account key / SFTP credentials), encrypted at rest by the platform encryption service (Global::editEncryptedField, the pattern SysEmailSMTPPassword uses). The key belongs to the environment, so any AOS or batch server decrypts it. Written through setAuthSecret, read only through MGCLatticeFileIngestSecretProtector::resolveConnectionSecret, and never displayed. Every save or decrypt writes a SysEncryptionLog audit row.
AuthSecretKvRefstring(255) (EDT MGCLatticeKeyVaultSecretUri)Label Key Vault reference. An Azure Key Vault secret URI, which is a reference rather than a secret; validateField refuses any other value.
ArchiveFolderPathstring(255)Folder an ingested source file is moved to; blank deletes it
ErrorFolderPathstring(255)Folder a file that cannot be ingested is moved to; blank leaves it in place
FileFormatenum MGCLatticeFileIngestFileFormatInbound file format
RecordPathstring(255)Identifies the records. XML: element name or element path (Order, /Orders/Order, Orders/Order), matched at any depth, namespaces ignored; blank = each child element of the root. JSON: JSON path with or without $ (orders, $.orders, $.orders[*]); blank = the root (an array gives one record per element). Not used for CSV and fixed width.
CsvDelimiter / CsvHasHeader / CsvQuoteCharstring / enum NoYes / stringCSV parser settings: delimiter (blank: comma; \t or tab: tab), header row (Yes on a new connection), quote character (blank: double quote; it opens a quoted field only as the first character of a field)
FixedWidthColumnSpecDirMemoJSON array of {"name","start","width"} column definitions for FixedWidth (required for that format; exactly these keys, start 0-based, width above 0, whole numbers)
TargetServiceClassstring(255)X++ class that receives transformed records; must implement MGCLatticeIFileIngestServiceTarget
TargetServiceOperationstring(80)Method on the target class invoked per record with the transformed content as its one str argument
LiquidTemplateDirMemoLiquid transform applied to each record (as JSON); blank sends the JSON record unchanged
Enabledenum NoYesOnly enabled connections are scanned by the pull job
MaxFilesPerRunintThe most files the pull ingests for the connection in one run; 0 means no limit
RetentionDaysintDays a complete bundle's file and staging data, and the record that the file was ingested, are kept before cleanup. initValue sets 30; 0 keeps them (with a warning); negative is refused
MinFileAgeSecondsint (EDT Seconds)Minimum file age (seconds): a file is picked up only when it was last written at least this many seconds ago, so a file that is still being uploaded is not ingested half-written. 0 means 60 seconds.
AllowedServiceOperationsDirMemoAllowed service operations: the operations the service-invoke target (MGCLatticeFileIngestServiceInvokeTarget) may call for this connection, one per line as ServiceClass.operation, or ServiceClass.* for every operation of a service. A routing envelope that names any other operation is rejected. Empty allows none, so a connection that uses the service-invoke target dispatches nothing until an administrator fills the list.
RequireStableSizeenum NoYesWait until the file size is stable: when Yes, a file is picked up only when its size is the same as on the previous run (see MGCLatticeFileIngestSizeObservation), so each file waits at least one more run; a size the store does not report never blocks. The wizard sets it to Yes for SFTP and File share and No for Azure Blob.

Secret-handling methods:

MethodSignatureDescription
setAuthSecretvoid setAuthSecret(MGCLatticeSecretValue _secret)Stores a secret on the buffer; the caller saves the record. A Key Vault secret URI is kept in AuthSecretKvRef; any other value is encrypted into AuthSecret and AuthSecretKvRef is cleared; an empty value clears both.
editAuthSecretedit MGCLatticeSecretValue editAuthSecret(boolean _set, MGCLatticeSecretValue _secret)Write-only edit method behind the Authentication field. Setting it calls setAuthSecret; reading it returns only a Key Vault reference, or an empty string, never the stored secret.
authSecretStoragedisplay MGCLatticeFileIngestSecretStorage authSecretStorage()Display method behind the Secret storage field.
insert / updatevoid insert() / void update()Run the platform's encrypted-table hooks around the save.
validateFieldboolean validateField(FieldId _fieldIdToCheck)Refuses a Key Vault reference (AuthSecretKvRef, PgpPrivateKeyKvRef, PgpPassphraseKvRef) that is not a Key Vault secret URI and a negative MinFileAgeSeconds, MaxFilesPerRun or RetentionDays; warns at RetentionDays = 0.

MGCLatticeFileIngestConnectionLock​

A lease that lets only one pull run work on a connection at a time. One row per connection, created on first use. Primary key and alternate-key index ConnectionIdx (ConnectionId). SaveDataPerCompany=No. A run claims the lease (under a pessimistic lock, in its own short transaction) before it lists the connection's files, renews it before each file and releases it when done; a run that finds a live lease held by another run skips the connection. A lease that is not renewed expires after 60 minutes, so a crashed run never blocks a connection for good.

FieldTypeDescription
ConnectionIdstringThe connection the lease is for
LockOwnerGUIDThe run that holds the lease
LockedUntilUtcutcdatetimeWhen the lease expires unless renewed

MGCLatticeFileIngestSizeObservation​

The size a pull last saw for a source file of a connection with RequireStableSize set. One row per connection and file path; unique alternate-key index ConnectionFileIdx (ConnectionId, SourceFileNameHash). SaveDataPerCompany=No. A pull takes such a file only when its size equals the stored size; otherwise it stores the new size and leaves the file for the next run. The row is removed when the file is ingested or skipped as already ingested, and MGCLatticeFileIngestCleanup purges rows not refreshed for 7 days. Only the run that holds the connection's lease writes its rows.

FieldTypeDescription
ConnectionIdstringThe connection
SourceFileNamestring(1024)The source file's full path
SourceFileNameHashstring(44)Base64 SHA-256 of the path (part of the key)
SizeBytesint64The size seen on the last run
ObservedDateTimeUtcutcdatetimeWhen that size was recorded

MGCLatticeFileIngestBundle​

One record per ingested file (the claim-check holder). Primary key BundleId; index BundleIdx (BundleId); relation to MGCLatticeFileIngestConnection. DeleteAction cascades to MGCLatticeFileIngestSegment. A bundle has no state of its own: it is complete when all its segments are Processed.

FieldTypeDescription
BundleIdstring(60)Bundle identifier (PK)
ConnectionIdstringOwning connection
SourceFileNamestring(1024)The source file's full path (a longer path is refused)
ClaimDocuRefIdint64RecId of the DocuRef holding the claim-checked file (document type DocuType::typeFile())
FileSizeBytesint64File size in bytes
SegmentCountintNumber of segments produced from the file
ReceivedDateTimeutcdatetimeWhen the file was ingested

MGCLatticeFileIngestSegment​

Staging / top-picking work table. One record per extracted record, identified by its RecId (the segment id in the log, the monitor, the run context and the dead-letter queue). Unique key SegmentBundleIdx (BundleId, Sequence); indexes SegmentQueueIdx (State, RecId - the top-picking claim) and SegmentRetryIdx (State, NextAttemptDateTime); relation to MGCLatticeFileIngestBundle.

FieldTypeDescription
BundleIdstringOwning bundle
SequenceintPosition of the record within the file
RawContentDirMemoExtracted record content as received (an XML record stays XML; JSON, CSV and fixed-width records are JSON)
TransformedContentDirMemoLiquid-rendered payload sent to the target
Stateenum MGCLatticeFileIngestStatePer-segment processing state
ProcessingAttemptsintNumber of processing attempts (retried until the cap of 3)
NextAttemptDateTimeutcdatetimeWhen a retried segment becomes eligible again
ErrorCode / ErrorCategoryenumClassified error of the last failure
ErrorMessageDirMemoLast error message, if any
RequestIdGUIDThe RequestId the service-invoke target sent the record with

MGCLatticeFileIngestLog​

Diagnostic log written by the pull, processing, and cleanup jobs. No primary key; relations to the connection and the bundle. Exposed read-only as the OData entity LatticeFileIngestLogs (MGCLatticeFileIngestLogEntity: FileIngestLogRecId, LogLevel, ConnectionId, BundleId, SegmentId, Message, Details, LoggedDateTime).

FieldTypeDescription
LogLevelenum MGCLatticeLogLevelSeverity (Info, Warning, Error)
ConnectionIdstringRelated connection
BundleIdstringRelated bundle
SegmentIdint64Related segment (its RecId)
MessageDirMemoLog message
DetailsDirMemoAdditional detail

MGCLatticeFileIngestProcessedFile​

Content-based dedup guard for the pull. One record per file that has already been ingested, so a re-pull of an unchanged file (e.g. after a post-commit source archive or delete failed) does not create a duplicate. The pull checks this table before ingesting a file and skips a match; when the hash cannot be computed it fails open and processes the file. The row is inserted in the same transaction as the bundle, so two concurrent runs that ingest the same file collide on the unique index and the second one rolls back. Unique primary index DedupIdx (ConnectionId, SourceFileNameHash, FileHash); index ConnectionCreatedIdx (ConnectionId, CreatedDateTime); the RecId index is clustered. SaveDataPerCompany=No. MGCLatticeFileIngestCleanup removes records older than the connection's RetentionDays, and the connection page's Ingested files FastTab lists them and lets an administrator delete one. Static helpers: computeFileHash(path) (streamed Base64 SHA-256 of a local file), pathHash(fileName), isProcessed(connectionId, fileName, fileHash), recordProcessed(connectionId, fileName, fileHash, bundleId) and purgeOlderThan(connectionId, threshold).

FieldTypeDescription
ConnectionIdstringOwning connection (part of the dedup key)
SourceFileNamestring(1024)The source file's full path
SourceFileNameHashstring(44)Base64 SHA-256 of the full path (part of the dedup key)
FileHashstring(44)Base64-encoded SHA-256 hash of the file content (part of the dedup key)
BundleIdstringThe bundle the file produced

25.3 Classes​

All classes are created through a static construct().

MGCLatticeFileIngestPull​

Extends RunBaseBatch (canRunInNewSession=true). The scheduled pull job: for each enabled connection it claims the connection's lease (MGCLatticeFileIngestConnectionLock; a connection another run holds is skipped), lists matching files, downloads each one once to a temporary file, PGP-decrypts it when the connection's DecryptSourceFiles is set, claim-checks it into Document Management, inserts the bundle, the dedup row and one segment per record in a single transaction, then moves the source file to ArchiveFolderPath (or deletes it when the connection has none). A file is ingested only when it was last written at least MinFileAgeSeconds ago, then (with RequireStableSize) its size is the same as on the previous run, its path has at most 1,024 characters, and it was not already ingested with the same path and content (an already ingested file is archived or deleted at the source instead). A file that is empty, produces no records, or fails any step is logged as an error and moved to ErrorFolderPath, or left in the source folder and retried by the next run when there is none; only a committed file is archived or deleted. At most MaxFilesPerRun files are ingested per connection and run (0: no limit). The pull never updates the connection record.

MethodSignatureDescription
constructstatic MGCLatticeFileIngestPull construct()Factory
descriptionstatic ClassDescription description()RunBase caption
runvoid run()Executes the pull
mainstatic void main(Args _args)Menu-item entry point
pack / unpackcontainer pack() / boolean unpack(container _packedClass)RunBase state persistence

MGCLatticeFileIngestSegmentController / MGCLatticeFileIngestSegmentService​

MGCLatticeFileIngestSegmentController extends SysOperationServiceController and starts the segment processor as a reliable asynchronous batch operation; its action menu item Process file ingestion segments is at System administration > Periodic tasks > Lattice, and started from there it checks the Lattice license first. MGCLatticeFileIngestSegmentService extends SysOperationServiceBase and implements BatchRetryable; it runs the top-picking loop (select firstonly forupdate pessimisticlock with readPast(true)) so multiple batch tasks drain the staging table in parallel without contention. For each claimed segment it builds the request with transformRecord, dispatches, and marks the segment Processed, storing the RequestId the service-invoke target sent and logging the operation's message (a warning when the RequestId had been claimed by an earlier request, i.e. a replay); on error it increments ProcessingAttempts and marks Failed past the cap of 3.

ClassMethodSignatureDescription
Controllerconstructstatic MGCLatticeFileIngestSegmentController construct()Factory
Controllermainstatic void main(Args _args)Entry point
Serviceconstructstatic MGCLatticeFileIngestSegmentService construct()Factory
ServiceisRetryableboolean isRetryable()Returns true (BatchRetryable contract)
ServiceprocessSegmentsvoid processSegments()Top-picking drain loop
ServicerecordJsonstatic str recordJson(MGCLatticeFileIngestConnection _connection, str _rawContent)The stored record as JSON: a record of an XML connection that starts with < is converted with FileIngestionService.ConvertXmlToJson (the record element omitted, attributes and child elements as properties without namespace prefixes); anything else is returned unchanged
ServicetransformRecordstatic str transformRecord(MGCLatticeFileIngestConnection _connection, str _rawContent)recordJson, then the connection's Liquid template rendered against it with $xref placeholders resolved (output that holds placeholders must be strict JSON first); with a blank template the JSON record is returned unchanged

MGCLatticeFileIngestCleanup​

Extends RunBaseBatch. For every bundle whose segments are all Processed (checked with a notexists join on the segments) and that is older than its connection's RetentionDays, deletes the claim-checked file (via the DocuRef, removing the backing blob) and the bundle plus its cascaded segments. It also removes the MGCLatticeFileIngestProcessedFile records older than the connection's RetentionDays. Retention of 0 is treated as a guard and skips deletion. Each run also purges the MGCLatticeFileIngestSizeObservation rows not refreshed for 7 days.

MethodSignatureDescription
constructstatic MGCLatticeFileIngestCleanup construct()Factory
canRunInNewSessionboolean canRunInNewSession()Batch session support
runvoid run()Executes the cleanup
mainstatic void main(Args _args)Entry point

Parsers - MGCLatticeFileIngestParser / Xml / Json / Csv / FixedWidth / Factory​

MGCLatticeFileIngestParser is the abstract base; MGCLatticeFileIngestXmlParser, MGCLatticeFileIngestJsonParser, MGCLatticeFileIngestCsvParser and MGCLatticeFileIngestFixedWidthParser split a file into per-record raw fragments. The XML parser returns the outer XML of each element its element path matches; the JSON parser evaluates its record path with Newtonsoft's SelectTokens (a single selected array gives one record per element, several matches one record each). MGCLatticeFileIngestCsvParser treats each delimited row as a record and MGCLatticeFileIngestFixedWidthParser each non-blank line, and both normalize it to JSON (ConvertCsvToJson / ConvertFixedWidthToJson) so the same Liquid transform pipeline applies uniformly across formats. MGCLatticeFileIngestParserFactory selects the parser by file format; constructForConnection configures it from the connection.

ClassMethodSignatureDescription
Parser (abstract)parmRecordPathstr parmRecordPath(str _recordPath = recordPath)Gets/sets the record path
Parser (abstract)parseRecordsabstract List parseRecords(str _content)Splits file content into per-record fragments
XmlrecordXPathstatic str recordXPath(str _recordPath)The namespace-agnostic XPath of an element path (Orders/Order → //*[local-name()="Orders"]/*[local-name()="Order"]); empty for a blank path
XmlisValidRecordPathstatic boolean isValidRecordPath(str _recordPath)True when every step is an XML element name (no predicates, attributes, wildcards or prefixes); blank is valid
JsonrecordPathErrorstatic str recordPathError(str _recordPath)Empty when the JSON path is valid (or blank); otherwise the parser's reason
CsvparmDelimiter / parmHasHeader / parmQuoteCharstr parmDelimiter(str), NoYes parmHasHeader(NoYes), str parmQuoteChar(str)Delimited settings; the defaults are comma, header row and double quote
FixedWidthparmColumnSpecstr parmColumnSpec(str _columnSpec = columnSpec)The {name,start,width} column specification; parsing without one throws
Factoryconstructstatic MGCLatticeFileIngestParser construct(MGCLatticeFileIngestFileFormat _format, str _recordPath)Returns the parser for the format with the record path set and no connection settings
FactoryconstructForConnectionstatic MGCLatticeFileIngestParser constructForConnection(MGCLatticeFileIngestConnection _connection)Returns the parser for the connection's format with its record path, CSV settings and fixed-width column specification; used by the pull

Dispatchers - MGCLatticeFileIngestDispatcher / CustomServiceDispatcher / Factory​

MGCLatticeFileIngestDispatcher is the abstract dispatch interface; MGCLatticeFileIngestCustomServiceDispatcher invokes the connection's TargetServiceClass/TargetServiceOperation. When that target is the service-invoke target (MGCLatticeFileIngestServiceInvokeTarget), the dispatcher passes it the connection's AllowedServiceOperations, and a routing envelope that names an operation not on that list is rejected before anything is called. MGCLatticeFileIngestDispatcherFactory resolves the dispatcher for a connection. For the service-invoke target the custom-service dispatcher also exposes, after each call, parmLastRequestId, parmLastResultMessage and parmLastWasReplay.

MGCLatticeFileIngestServiceInvokeTarget​

The shipped target (handleIngestedContent). parseEnvelope reads the routing envelope strictly: one RFC 8259 JSON object (FileIngestionService.ValidateStrictJson), no member name repeated in any casing, root members only service, operation, requestKey and request (spelled exactly), service/operation strings and requestKey a string or a whole number. The allow-list is checked first. requestWithRunContext fills RequestId, LegalEntityId, UserContext and CorrelationId when the request leaves them empty and rejects a RequestId or CorrelationId that is not a GUID. runRequestId derives the name-based GUID of requestKey|<connection>|<legal entity>|<service>.<operation>|<key> (legal entity: the template's LegalEntityId, else the processing company), or of segment|<connection>|<bundle>|<segment RecId> without a key. previewIngestedContent runs everything except the posting for the simulator: a new random RequestId, then the operation in preview mode when its request contract implements MGCLatticeIPreviewableRequest, otherwise only the request contract is built.

ClassMethodSignatureDescription
Dispatcher (abstract)dispatchabstract boolean dispatch(str _transformedContent, MGCLatticeFileIngestConnection _connection, str _bundleId, int64 _segmentId)Delivers a transformed payload; returns true on success
Factoryconstructstatic MGCLatticeFileIngestDispatcher construct(MGCLatticeFileIngestConnection _connection)Returns the dispatcher for the connection

MGCLatticeFileIngestLogger​

Helper that writes MGCLatticeFileIngestLog records.

MethodSignatureDescription
constructstatic MGCLatticeFileIngestLogger construct()Factory
logstatic void log(MGCLatticeLogLevel _level, str _connectionId, str _bundleId, int64 _segmentId, str _message, str _details = '')Inserts a log record; _segmentId is the segment's RecId

MGCLatticeFileIngestSecretProtector​

The single entry point for reading a connection secret, and the helpers that tell how a connection stores it. The secret itself is encrypted by the platform encryption service in MGCLatticeFileIngestConnection.AuthSecret (see the table above); a Key Vault reference in AuthSecretKvRef is fetched live from Key Vault (Key Vault secrets).

MethodSignatureDescription
resolveConnectionSecretstatic str resolveConnectionSecret(MGCLatticeFileIngestConnection _conn)Returns the plaintext secret: decrypts AuthSecret, or fetches a Key Vault reference from Key Vault (a failure raises FileIngestKeyVaultResolveFailed; a reference that is not a Key Vault secret URI is refused). Returns an empty string when the connection has no secret. Used by the pull jobs, Test connection and the APIM bulk export upload.
storagestatic MGCLatticeFileIngestSecretStorage storage(MGCLatticeFileIngestConnection _conn)Encrypted, KeyVaultReference or None.
isKeyVaultReferencestatic boolean isKeyVaultReference(str _stored)True for a secret URI of the form https://{vault}.vault.azure.net/secrets/{name}[/{version}], or the same on .vault.azure.cn, .vault.usgovcloudapi.net or .vault.microsoftazure.de, on the default port. Any other value, including one that only contains .vault.azure.net/secrets/, is not a Key Vault reference.

25.4 Forms​

FormPurpose
MGCLatticeFileIngestConnectionSetup grid + detail for connections, including the Liquid template editor, the write-only Authentication field (it stays empty after saving; type into it only to replace the secret, or enter {} to switch an Azure Blob connection to the managed identity) and the read-only Secret storage field; the Ingested files FastTab lists MGCLatticeFileIngestProcessedFile rows of the connection and lets an administrator delete one
MGCLatticeFileIngestBundleInquiryRead-only monitor: bundles → segments (with their request ID) → log
MGCLatticeLiquidTesterDiagnostic form (no data source) for authoring/testing Liquid templates: paste a template and a JSON payload, click Render, and the rendered output (or the error) is shown. Renders via FileIngestionService.RenderTemplate. Opened by the MGCLatticeLiquidTester display menu item.

25.5 Security​

ArtifactTypeGrants
MGCLatticeFileIngestMaintainPrivilegeMaintain connections (Create/Read/Update/Delete on the connection menu item) and Invoke the pull, segment processor, and cleanup actions
MGCLatticeFileIngestViewPrivilegeRead-only access to the bundle inquiry monitor
MGCLatticeFileIngestOperationsViewPrivilegeRead-only access to the file ingestion operations workspace and its list parts
MGCLatticeFileIngestDutyDutyBundles the three privileges above (MGCLatticeFileIngestMaintain, MGCLatticeFileIngestView, MGCLatticeFileIngestOperationsView)
MGCLatticeFileIngestSimulatorDutyDutyBundles MGCLatticeFileIngestSimulatorPrivilege (the simulator and sample payloads); held by the administrator and operator roles

25.6 C# Interop Library - Tools/MGCLatticeFileIngestion​

A net472 library (legacy .csproj) that provides streaming cloud-storage access and Liquid rendering for the X++ pull and processing jobs. All members are synchronous and use interop-friendly types so they can be called directly from X++.

FileIngestionService​

Public façade and X++ entry point. Each file operation constructs a single ICloudFileSource via CloudFileSourceFactory and disposes it before returning. storageType is "Blob", "FileShare", or "Sftp" (case-insensitive; "File"/"Share" alias to FileShare and "Ftp" to Sftp).

MethodSignatureDescription
ListFilesstring[] ListFiles(string storageType, string connectionJson, string path, string pattern)Lists files at the location matching the wildcard pattern (empty pattern matches all)
DownloadToStringstring DownloadToString(string storageType, string connectionJson, string path)Downloads a file and returns its contents decoded as UTF-8 (for small to moderate files)
DownloadToTempFilestring DownloadToTempFile(string storageType, string connectionJson, string path)Streams a file to a local temp file and returns its absolute path (for very large files); caller deletes it
DeleteFilebool DeleteFile(string storageType, string connectionJson, string path)Deletes a file if it exists; returns true when a file was deleted
MoveFilevoid MoveFile(string storageType, string connectionJson, string sourcePath, string destinationFolder)Moves a file into a folder; the pull uses it for the archive and error folders. On SFTP a destination that is the same file as the source is left alone, and a missing source fails before the destination is touched
GetFileAgeSecondslong GetFileAgeSeconds(string storageType, string connectionJson, string path)Whole seconds since the file was last written: -1 when the store reports no last-write time, 0 when the last-write time is in the future (clock skew). The pull compares it with MinFileAgeSeconds.
GetFileSizeByteslong GetFileSizeBytes(string storageType, string connectionJson, string path)The file's current size in bytes, or -1 when the store does not report it; used for the RequireStableSize check
ExtractRoutedOperationsstatic string[] ExtractRoutedOperations(string text)The distinct Service.operation entries a routing envelope or Liquid template calls, from literal "service" / "operation" pairs; names written by a Liquid expression are skipped.
RenderTemplatestring RenderTemplate(string templateText, string jsonData)Renders a Liquid template against JSON data (delegates to LiquidTransformer)
ConvertXmlToJsonstring ConvertXmlToJson(string xml)XML to JSON with the root element omitted, namespace prefixes and declarations dropped, CDATA as text, attributes as plain properties (@name only when a child element has the same name), and an element with text and attributes as its text plus Element_attribute properties; used by the segment processor for each XML record
ConvertCsvToJson / ConvertFixedWidthToJsonstring ConvertCsvToJson(string csv, string delimiter, bool hasHeader, string quoteChar) / string ConvertFixedWidthToJson(string content, string columnSpecJson)Delimited or fixed-width text to a JSON array of row objects; used by the CSV and fixed-width parsers. CSV: a quote opens a quoted field only at the start of a field, an unterminated quoted field throws, and the delimiter \t or tab means a tab. Fixed width: the specification must be a non-empty array of objects with exactly name, integer start (0 or more) and integer width (above 0); lines split on CRLF, LF or CR
ValidateStrictJsonstring ValidateStrictJson(string json)Empty when the text is exactly one RFC 8259 JSON value and no object repeats a member name (compared without case); otherwise the reason with line and position. Never throws. Used by the service-invoke target and before $xref resolution
ResolveKeyVaultSecretstring ResolveKeyVaultSecret(string secretUri)Fetches a Key Vault secret's value with a DefaultAzureCredential token (the AOS managed identity); used by MGCLatticeFileIngestSecretProtector::resolveConnectionSecret for Key Vault references (see Key Vault secrets). A value that is not a Key Vault secret URI (IsKeyVaultSecretUri) is rejected before any token is requested.
IsKeyVaultSecretUristatic bool IsKeyVaultSecretUri(string value)True for an https URI with no user info, on the default port, whose host is a vault under .vault.azure.net, .vault.azure.cn, .vault.usgovcloudapi.net or .vault.microsoftazure.de and whose path is /secrets/{name} or /secrets/{name}/{version}
DecryptSourceFilebyte[] DecryptSourceFile(byte[] cipher, string privateKeyKvRef, string passphraseKvRef)PGP-decrypts a pulled file with a private key and passphrase resolved from Key Vault references. The message must be integrity-protected; a tampered or unprotected message fails. Signatures are not verified.

ICloudFileSource + sources + factory​

ICloudFileSource : IDisposable is the streaming storage abstraction (never materializes whole files as byte arrays). Implementations: AzureBlobFileSource, AzureFileShareFileSource, SftpFileSource. SftpFileSource resolves every folder and file path against its root path, the connection's container setting (SftpFileSource.ResolvePath(rootPath, path)): a path that starts with / is used as is, a relative path is placed under the root, a blank path is the root, and without a root a relative path is relative to the login directory. The same rule applies to the destination folder of MoveFile (the archive and error folders).

MemberSignatureDescription
ListFilesIEnumerable<string> ListFiles(string path, string pattern)Enumerates matching file names (lazily where supported)
OpenReadStream OpenRead(string path)Opens a forward-only read stream (caller disposes)
DeleteFilebool DeleteFile(string path)Deletes the file if it exists
CloudFileSourceFactory.Createstatic ICloudFileSource Create(string storageType, string connectionJson)Builds the source for a storage type; throws ArgumentException for unknown types

Connection settings are parsed by CloudFileSourceSettings.Parse(string connectionJson), which accepts case-insensitive keys and common aliases (connectionString, endpoint, accountName/accountKey, sasToken, container/share - for SFTP the root path, host, username, password, privateKey, port; SFTP port defaults to 22).

LiquidTransformer​

Renders Liquid templates against JSON using the Fluid engine. Parsed templates are cached (keyed by a SHA-256 hash of the template text) for parse-once / render-many throughput; the JSON is converted to nested dictionaries/lists so Fluid's secure-by-default member access works without registering CLR types.

Every {{ ... }} output is escaped for use inside a JSON string (" becomes \", \ becomes \\, ' becomes ', control characters become \uXXXX), so a quote in the data cannot close its string and change the request; literal template text is never encoded. Use {{ x | number }} for a number in an unquoted position (blank: null; decimal text, including zero-padded text, becomes a JSON number; anything else fails the render), {{ x | as_array }} to loop over a value that may be one object or a list, {{ x | json }} to insert a complete JSON value (an array or an object), and {{ x | raw }} only for trusted values.

MethodSignatureDescription
Renderstring Render(string templateText, string jsonData)Renders the template against the JSON model; throws InvalidOperationException on a parse error or invalid JSON

26. OData Entity Metadata Explorer​

A discovery and documentation tool for the public OData data entities published by D365 F&O. It enumerates public entities, captures their fields, exposed (bound) methods, and method parameters, generates sample GET/POST/PATCH payloads, and surfaces everything in a workspace form. The captured metadata also feeds the C# documentation generator to produce Postman collections and OpenAPI specs.

26.1 Enums​

MGCLatticeLogLevel - severity of an MGCLatticeODataRefreshLog entry (Info, Warning, Error; shared by all three log tables, see Log Level Enum).

26.2 Tables​

MGCLatticeODataEntityMetadata​

One record per discovered public OData entity. Primary key on EntityName; index EntityNameIdx. DeleteActions cascade to MGCLatticeODataFieldMetadata and MGCLatticeODataEntityMethod.

FieldTypeDescription
EntityNamestringData entity (AOT) name (PK)
PublicCollectionNamestringOData collection name (the /data/{name} set)
PublicEntityNamestringOData singular public entity name
EntityTablestringBacking table: the table of the root data source of the entity
EntityCategoryenum EntityCategoryEntity category
SysModuleenum DMFModuleOwning module (System administration when the entity names a module that DMFModule does not have)
TagsstringEntity tags
IsObsoleteenum NoYesMarked obsolete
DescriptionstringDescription
PackageNamestringOwning package/model
IsCustomenum NoYesCustom (non-Microsoft) entity
IsPublicenum NoYesExposed as a public OData entity
IsReadOnlyenum NoYesThe entity is read-only
PrimaryKeystringThe fields of the entity key, comma-separated in key order
ContentHashstringHash of the entity's metadata signature (entity, fields, methods); a refresh rewrites the entity only when it changed
FieldCountintNumber of fields
MethodCountintNumber of exposed methods

MGCLatticeODataFieldMetadata​

One record per field on an entity. Index EntityFieldIdx; relation to MGCLatticeODataEntityMetadata.

FieldTypeDescription
EntityNamestringOwning entity
FieldNamestringField name
DataTypestringBase data type
ExtendedDataTypestringEDT, if any
EnumTypestringEnum type, if any
LabelstringField label
IsMandatoryenum NoYesField is mandatory
IsKeyenum NoYesField participates in the entity key
AllowEditenum NoYesField is editable
IsObsoleteenum NoYesField is marked obsolete
PositionintOrdinal position of the field on the entity

MGCLatticeODataEntityMethod​

One record per OData-exposed (bound/unbound) method on an entity. Index EntityMethodIdx; relation to MGCLatticeODataEntityMetadata. DeleteActions cascade to MGCLatticeODataEntityMethodParameter.

FieldTypeDescription
EntityNamestringOwning entity
MethodNamestringX++ method name
ODataActionNamestringOData action/function name
IsBoundenum NoYesWhether the action is bound to the entity
ReturnTypestringReturn type
ParameterCountintNumber of parameters
SampleRequestJsonstringGenerated sample request body
SampleResponseJsonstringGenerated sample response body

MGCLatticeODataEntityMethodParameter​

One record per parameter of an exposed method. Index MethodParamIdx; relation to MGCLatticeODataEntityMethod.

FieldTypeDescription
EntityNamestringOwning entity
MethodNamestringOwning method
ParameterNamestringParameter name
PositionintOrdinal position
DataTypestringParameter data type
ContractClassNamestringData contract class, when the parameter is a contract
IsContractenum NoYesWhether the parameter is a data contract

MGCLatticeODataRefreshLog​

Diagnostic log written during a metadata refresh. No primary key. Rows are emitted by the instrumented discovery pipeline: Info rows record stage start/completion and summary counters (e.g. X enumerated, Y public, Z processed, N failed); Warning rows record silently-degraded values (e.g. a sample-value conversion that fell back to a heuristic, an unreadable field/method); Error rows record a failed element (named in EntityName/FieldName) or a run-level failure, with the failing step in Message and the full CLR/infolog exception text in Details. The refresh continues past failed elements, so a single bad entity does not abort discovery. Filter LogLevel = Error to pinpoint failures.

FieldTypeDescription
LogLevelenum MGCLatticeLogLevelSeverity (Info, Warning, Error)
EntityNamestringRelated entity (clamped to 255 chars by the logger)
FieldNamestringRelated field (clamped to 255 chars by the logger)
MessagestringLog message, including the failing step for error rows
DetailsstringAdditional detail - for error rows, the CLR exception ToString() or captured infolog text

26.3 Classes​

MGCLatticeODataMetadataDiscovery​

Discovers public OData data entities and populates the metadata tables. Follows the public new() + static construct() pattern.

MethodSignatureDescription
constructstatic MGCLatticeODataMetadataDiscovery construct()Factory
refreshAllstatic void refreshAll()Clears the refresh log (in its own committed transaction) and rediscovers all public data entities by delta: an entity whose ContentHash is unchanged is left as it is, and only new, changed and removed entities are written. Discovery runs outside any transaction so per-element error handlers fire and diagnostic log rows survive
logRunErrorstatic void logRunError(str _message, str _details = '')Persists a run-level Error row to MGCLatticeODataRefreshLog. Public so the batch wrapper - which runs with no active transaction - can record a top-level failure (with full exception detail) that survives the failed run instead of surfacing an opaque, log-less error

Diagnostic behavior. The discovery pipeline is instrumented for diagnosability and writes structured rows to MGCLatticeODataRefreshLog (see 26.2 Tables):

  • Catch-and-continue per element. Each entity, field, exposed method, and method parameter is processed under its own try/catch. A failure on one element is logged with the element name and the precise step that failed, then discovery continues with the next element rather than aborting the whole refresh.
  • Step-tracked error rows. Every risky stage updates a step tracker (e.g. discoverFields, fetchSampleRecord, inserting entity record) so the logged row names both the failing element and the stage. CLR faults capture CLRInterop::getLastException().ToString() in Details; X++ errors capture the infolog text.
  • Run-level trap. refreshAll() runs the log clear in its own committed transaction, then runs discovery and the change-summary logic under a run-level try/catch (outside any transaction) that logs an Error row naming the run step and re-throws so the batch is still reported as failed.
  • Guarded log writes. The internal logger truncates the bounded EntityName/FieldName columns and never throws, so a logging failure can never mask the original exception being recorded.
  • Summary counters. Each stage emits an Info summary row (e.g. Discovery complete: X enumerated, Y public, Z processed, N failed), and silently-degraded values (e.g. a sample-value conversion that falls back to a heuristic) are recorded as Warning rows naming the field.

MGCLatticeODataMetadataRefreshBatch​

Extends RunBaseBatch. Wraps MGCLatticeODataMetadataDiscovery::refreshAll() so the refresh can be scheduled as a batch job.

MethodSignatureDescription
constructstatic MGCLatticeODataMetadataRefreshBatch construct()Factory
runvoid run()Runs the metadata refresh. On failure it calls MGCLatticeODataMetadataDiscovery::logRunError(...) to persist a step-tracked, non-rolled-back Error row to MGCLatticeODataRefreshLog (with full exception detail), surfaces a pointer to the log via error(...), then re-throws so the batch is reported as failed
descriptionstatic ClassDescription description()RunBase caption
mainstatic void main(Args _args)Entry point
pack / unpackcontainer pack() / boolean unpack(container _packedClass)RunBase state persistence

26.4 Form​

FormPurpose
MGCLatticeODataEntityMetadataExplorerWorkspace to browse discovered entities, their fields, methods, parameters, and generated sample payloads; includes a refresh action

26.5 Security​

ArtifactTypeGrants
MGCLatticeODataEntityMetadataExplorerPrivilegePrivilegeRead access to the explorer form and Invoke/Read/Delete on the metadata refresh action
MGCLatticeODataEntityMetadataExplorerDutyDutyBundles MGCLatticeODataEntityMetadataExplorerPrivilege

26.6 C# Documentation Generator - OData support​

The MGCLatticeDocumentationGenerator library consumes an exported OData entity metadata payload (ODataMetadataExport) and produces Postman and OpenAPI documents for the discovered entities.

ODataPostmanGenerator and ODataOpenApiGenerator each expose:

GeneratorMethodOutput
ODataPostmanGeneratorstatic string Generate(ODataMetadataExport metadata)Postman v2.1 collection JSON
ODataOpenApiGeneratorstatic string Generate(ODataMetadataExport metadata)OpenAPI 3.0.3 specification JSON

DocumentationService provides OData-specific entry points (in addition to its service-metadata methods):

MethodSignatureDescription
GenerateODataPostmanFromJsonstring GenerateODataPostmanFromJson(string odataMetadataJson)Postman collection from an OData metadata JSON payload
GenerateODataOpenApiFromJsonstring GenerateODataOpenApiFromJson(string odataMetadataJson)OpenAPI spec from an OData metadata JSON payload
GenerateODataPostmanFromJsonstring GenerateODataPostmanFromJson(string odataMetadataJson, string packageFilter)As above, restricted to entities whose PackageName matches packageFilter (case-insensitive)
GenerateODataOpenApiFromJsonstring GenerateODataOpenApiFromJson(string odataMetadataJson, string packageFilter)As above, restricted to a single package

The generator makes no network calls: X++ builds the metadata JSON from the Lattice metadata tables and passes it to these methods and to the service-metadata *FromJson methods.


27. Price Inquiry Service​

Service: MGCLatticePriceInquiryService Service Group: MGCLatticeAccountsReceivableServiceGroup

Read-only inquiry that resolves the effective sales price for a customer + item + date + quantity by wrapping the classic PriceDisc engine (findPrice), which walks the sales trade-agreement hierarchy for the customer's price group and falls back to the item base price. It commits nothing and makes no idempotency claim (a point query). Line/multiline discount resolution, purchase pricing, and the GlobalUnifiedPricing path are not covered.

resolveSalesPrice​

Request Contract: MGCLatticePriceInquiryRequestContract

FieldJSON KeyTypeRequiredDescription
Correlation IDCorrelationIdGUIDNoEchoed on the response for distributed tracing
Legal EntityLegalEntityIdstringNoCompany to resolve the price in; empty uses the caller's current company. A company that does not exist is refused (ValidationFailed).
Customer AccountCustAccountstringYesCustomer whose price group drives the agreement search
Item IDItemIdstringYesItem to price
Customer Account keyCustAccountExternalKeystringNoThe customer's alternate key in ExternalSystem, used in place of CustAccount.
Item ID keyItemIdExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemId.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
QuantityQtydecimalNoQuantity break to evaluate (defaults to 1)
Price DatePriceDatedateNoEffective date (defaults to today's date in the calling user's time zone)
Currency CodeCurrencyCodestringNoCurrency (defaults to the customer currency)
Unit IDUnitIdstringNoUnit of measure (defaults to the item's sales unit)
SiteSiteIdstringNoSite dimension for site-specific agreements
WarehouseWarehouseIdstringNoWarehouse dimension

The inquiry is a read: it has no RequestId, makes no idempotency claim and is not license-gated.

Response Contract: MGCLatticePriceInquiryResponseContract - a lean envelope (not the common MGCLatticeOrderOperationResponseContract):

FieldJSON KeyTypeDescription
SuccessSuccessbooleanWhether the inquiry executed without error
MessageMessagestringResult / error text
Correlation IDCorrelationIdGUIDThe request's correlation id
Error CodeErrorCodeintegerMGCLatticeServiceErrorCode (see Status Enums); 0 None on success. 1 ValidationFailed: missing customer or item, unknown legal entity, or an external key that does not resolve. 2 DocumentNotFound: the customer or item does not exist in the company. 4 BusinessRule: the pricing engine refused. 6 TransientRuntime: a runtime fault. 13 UnexpectedError: any other exception.
ErrorsErrorsstring[]The error lines the inquiry raised; empty on success
Price FoundPriceFoundbooleantrue when an agreement or base price resolved
Unit PriceUnitPricedecimalResolved effective price
Price UnitPriceUnitdecimalPrice-per quantity basis (e.g. price per 100)
Source Agreement RecIdSourceAgreementRecIdintegerRecId of the winning PriceDiscTable row; 0 means the item base price was used
Applied Currency CodeAppliedCurrencyCodestringCurrency actually applied
Applied DateAppliedDatedateDate actually applied
Applied QuantityAppliedQtydecimalQuantity actually applied
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"LegalEntityId": "USMF",
"CustAccount": "US-001",
"ItemId": "D0001",
"Qty": 10.0,
"PriceDate": "2026-01-15",
"CurrencyCode": "USD"
}
}

28. Sales Trade Agreement Service​

Service: MGCLatticeSalesTradeAgreementService (extends MGCLatticeOrderPostingServiceBase) Service Group: MGCLatticeAccountsReceivableServiceGroup Security: MGCLatticeSalesTradeAgreementServiceMaintain (privilege) - grants Invoke on both operations below. To read the effective price, use resolveSalesPrice (section 27).

Creates and posts sales-price trade agreements (PriceDiscTable) with clean, forward-only supersession. Each request builds a PriceDiscAdmTable/PriceDiscAdmTrans journal and posts it through PriceDiscAdmCheckPost, resolving to exactly one MGCLatticeTradeAgreementOutcome.

Timeline engine: one open-ended row + the same FromDate → edited in place; a later FromDate → the prior row is capped (ToDate = FromDate − 1) and a new row added (superseded), in a single journal; a semantically identical request (same key, FromDate, unit price, price unit and open-endedness) → unchanged, nothing is posted; any other timeline is complex - no open-ended row for the key (a first price for the key included), more than one, or a FromDate before the open-ended row's - and is rejected (RejectedComplex, BusinessRule) unless FindNext is true, which makes it a plain create (created). Idempotency is semantic: the request has no RequestId, and repeating an applied request answers Unchanged. Batch = one journal per request; purchase pricing, discounts, and back-dating are not supported.

MGCLatticeTradeAgreementOutcome (enum)​

ValueNumericDescription
None0No outcome (never returned by a completed call)
Created1A new price row was inserted (a complex timeline with FindNext true, for example the first price for a key)
EditedInPlace2An existing same-FromDate row was updated
Superseded3A prior row was capped and a new row added
RejectedComplex4The existing timeline was too complex to change safely; nothing was created
Unchanged5The requested price is already effective; nothing changed
Failed6The request was refused or the create/post failed, including a trade agreement journal that was created but did not post. A sales price whose item, account, currency or unit fails the standard trade agreement line validation is refused with this outcome; nothing is posted. ErrorCode says why.

Success is true only for the outcomes that leave the requested price effective: Created, EditedInPlace, Superseded and Unchanged. RejectedComplex and Failed answer Success false. The enum is not extensible; its integers are the wire values.

setSalesPrice​

Request Contract: MGCLatticeSetSalesPriceRequest

FieldJSON KeyTypeRequiredDescription
Correlation IDCorrelationIdGUIDNoEchoed on the result for tracing
Legal EntityLegalEntityIdstringNoCompany to post the agreement in; empty uses the caller's current company. A company that does not exist is refused (ValidationFailed).
Account CodeAccountCodeinteger (enum PriceDiscPartyCodeType)YesParty scope, sent as a number: 0 Table (customer), 1 GroupId (price group), 2 All. The name ("Table") is refused with HTTP 400.
Account RelationAccountRelationstringYesCustomer account or price group (per AccountCode). With AccountCode 0 the customer must exist (DocumentNotFound otherwise).
Item CodeItemCodeinteger (enum PriceDiscProductCodeType)YesProduct scope, sent as a number: 0 Table (item), 1 GroupId (item group), 2 All.
Item RelationItemRelationstringYesItem number or item group (per ItemCode). With ItemCode 0 the item must exist (DocumentNotFound otherwise).
Account Relation keyAccountRelationExternalKeystringNoThe customer's alternate key in ExternalSystem, used in place of AccountRelation. Only with AccountCode = Table; refused otherwise.
Item Relation keyItemRelationExternalKeystringNoThe released product's alternate key in ExternalSystem, used in place of ItemRelation. Only with ItemCode = Table; refused otherwise.
External SystemExternalSystemstringNoThe external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with any ...ExternalKey member, including line keys. See Cross-reference keys.
Currency CodeCurrencyCodestringYesAgreement currency
Unit IDUnitIdstringNoUnit of measure; empty defaults to the item's sales unit when ItemCode is 0 (Table)
From QuantityFromQtydecimalNoQuantity break "from" (0 = all quantities)
Unit PriceUnitPricedecimalYesUnit price to set. Must be greater than zero; a zero price (also what an omitted UnitPrice reads as) is refused unless AllowZeroPrice is true. A negative price is always refused.
Allow Zero PriceAllowZeroPricebooleanNotrue to set a unit price of zero (a free item)
Price UnitPriceUnitdecimalNoPrice-per quantity basis (defaults to 1)
From DateFromDatedateYesEffective-from date (drives edit-vs-supersede); not earlier than today in the calling user's time zone
To DateToDatedateNoEffective-to date (empty = open-ended)
Find NextFindNextbooleanNotrue turns an otherwise-complex timeline into a plain create. Needed for the first price of a key (no open-ended price yet); without it that request is RejectedComplex
SiteSiteIdstringNoSite dimension
WarehouseWarehouseIdstringNoWarehouse dimension
Preview ModePreviewModebooleanNosetSalesPrice has no preview: true is refused with ErrorCode PreviewUnsupported before anything runs

Result Contract: MGCLatticeSetSalesPriceResult

FieldJSON KeyTypeDescription
SuccessSuccessbooleantrue for Created, EditedInPlace, Superseded and Unchanged; false for RejectedComplex and Failed
MessageMessagestringResult / error text
Correlation IDCorrelationIdGUIDThe request's correlation id
Error CodeErrorCodeintegerMGCLatticeServiceErrorCode; 0 None on success. 1 ValidationFailed (a missing or invalid member, a back-dated FromDate, an external key that does not resolve), 2 DocumentNotFound (customer or item), 4 BusinessRule (RejectedComplex, or the journal did not post), 6 TransientRuntime, 10 PreviewUnsupported, 11 ConfigurationMissing (no sales-price trade agreement journal name), 12 LicenseNotValid, 13 UnexpectedError
ErrorsErrorsstring[]The error lines raised; empty on success
OutcomeOutcomeintegerMGCLatticeTradeAgreementOutcome numeric value
Outcome NameOutcomeNamestringMGCLatticeTradeAgreementOutcome member name
Journal NumberJournalNumstringPrice/discount journal the agreement was posted under
Created Agreement RecIdCreatedAgreementRecIdintegerRecId of the newly created PriceDiscTable row
Superseded Agreement RecIdSupersededAgreementRecIdintegerRecId of the capped (superseded) row, if any
Superseded New To DateSupersededNewToDatedateThe new ToDate stamped on the superseded row
Applied From DateAppliedFromDatedateEffective-from date actually applied
Applied To DateAppliedToDatedateEffective-to date actually applied
Applied Unit PriceAppliedUnitPricedecimalUnit price actually applied
{
"_request": {
"CorrelationId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"LegalEntityId": "USMF",
"AccountCode": 0,
"AccountRelation": "US-001",
"ItemCode": 0,
"ItemRelation": "D0001",
"CurrencyCode": "USD",
"UnitPrice": 42.50,
"FromDate": "2026-02-01",
"FindNext": true
}
}

setSalesPriceBatch​

Accepts a List of MGCLatticeSetSalesPriceRequest (_requests) - one journal per request, each item independent - and returns MGCLatticeSetSalesPriceBatchResult:

FieldJSON KeyTypeDescription
SuccessSuccessbooleantrue when the list has items and every item succeeded
MessageMessagestringSummary ("N of M sales prices were applied.") or why the batch was refused
Total CountTotalCountintegerNumber of request items
Success CountSuccessCountintegerItems that succeeded
Failure CountFailureCountintegerItems that failed
ResultsResultsMGCLatticeSetSalesPriceResult[]One result per request item, in request order

A missing or empty list answers Success false with no results. A missing (null) item gets its own result with outcome Failed and ErrorCode ValidationFailed; the other items still run.

Emitted business events​

When a sales-price trade agreement changes, the post path (and a scheduled effectivity batch) publish six business events in the SalesOrder module. All six share one contract, MGCLatticeTradeAgreementPriceBusinessEventContract (extends MGCLatticeBusinessEventContractBase, inheriting the correlation-id / event-sequence / schema-version envelope), and the MGCLatticeTradeAgreementPriceChangeType enum (Created 0, Modified 1, Superseded 2, Deleted 3, Effective 4, Expired 5).

Event classFires when
MGCLatticeTradeAgreementPriceCreatedBusinessEventa posted journal line inserts a sales price for an agreement (including quantity break and dimensions) that had no sales price in effect on its From date
MGCLatticeTradeAgreementPriceModifiedBusinessEventa posted journal line changes at least one value of an existing sales price; the payload lists the changed fields
MGCLatticeTradeAgreementPriceSupersededBusinessEventa posted journal line adds a sales price for an agreement that already had a price in effect on its From date; the payload carries that price's amount and record ID
MGCLatticeTradeAgreementPriceDeletedBusinessEventa sales price is deleted by a user, by code, or by a posted journal line marked for deletion
MGCLatticeTradeAgreementPriceEffectiveBusinessEventthe effectivity batch reports, once and in date order, each sales price whose From date has been reached
MGCLatticeTradeAgreementPriceExpiredBusinessEventthe effectivity batch reports each sales price whose To date has passed when no other price of the same agreement is in effect the next day

MGCLatticeTradeAgreementPriceEffectivityBatch (RunBaseBatch) raises the Effective/Expired events daily, as the Lattice sales price effectivity events background process. The background process sweeps every legal entity that is not a virtual company, inside changecompany, so each event is raised in its price's legal entity; a run from the menu item covers the current legal entity only. It records its position per sweep in MGCLatticeTradeAgreementPriceEffectivityCursor, committing each event together with the position, so every price is reported once; while an event is not activated its sweep holds its position and catches up once activated. Each event is independently config-gated via BusinessEventsConfigurationReader. These journal-post-path events complement the pre-existing record-based MGCLatticeSalesPriceTradeAgreementChangedBusinessEvent (both coexist, each independently gated).


29. Just-In-Time Database Access Service​

Service: MGCLatticeDbAccessService Service Group: MGCLatticeDbAccessServiceGroup Security: MGCLatticeDbAccessAdminPrivilege (privilege-gated; the service also re-checks caller authorization in code - defense in depth).

Vends time-bound AxDB db_owner access to integration administrators. Unlike the posting services it uses its own request/response contracts (not the common response format), and because it grants full db_owner it is tightly gated. The password is generated server-side with a CSPRNG, stored encrypted at rest on the audit row by the platform encryption service (MGCLatticeDbAccessGrant.Password, so any AOS or batch server can decrypt it), and returned on the live response - never written to telemetry or any log.

requestAccess​

Validates the caller and the supplied public IPv4 address, revokes every active grant the caller holds (one active grant per administrator), writes the grant's audit row, provisions a new contained database user in db_owner plus a database firewall rule for the IP, stores the password encrypted on the audit row, and returns the password.

  • The audit row is committed before the database user and firewall rule are created, so a failed or interrupted request leaves a row that the expiry sweep cleans up. A failed request is rolled back and answers Success = false.
  • A prior grant that cannot be revoked at that moment does not block the new grant: it stays Active with its expiry moved to now, and the expiry sweep revokes it.

Request Contract: MGCLatticeDbAccessRequestContract

FieldJSON KeyTypeRequiredDescription
Correlation IDCorrelationIdstring (GUID)NoEchoed on the response
IP AddressIpAddressstringYesPublic IPv4 address to allowlist on the AxDB firewall
Duration HoursDurationHoursintegerNoGrant lifetime; defaults to 24, clamped to 1-72

Response Contract: MGCLatticeDbAccessResponseContract

FieldJSON KeyTypeDescription
Correlation IDCorrelationIdstring (GUID)Echoed from the request
SuccessSuccessbooleanWhether the request succeeded
Error CodeErrorCodeMGCLatticeServiceErrorCodeWhy a request failed: AccessDenied (the caller is not a database access administrator), LicenseNotValid, ValidationFailed (not a public IPv4 address), BusinessRule, TransientRuntime or UnexpectedError; None on success
MessageMessagestringNon-sensitive result message
UsernameUsernamestringProvisioned contained database user name
PasswordPasswordstringGenerated password - populated only on this live response; never persisted in cleartext or logged
Server NameServerNamestringAxDB server host to connect to (Azure SQL Database reports a short name; the response carries the full <server>.database.windows.net)
Database NameDatabaseNamestringAxDB database to connect to
ExpiresExpiresDateTimeUtcdatetimeWhen the grant expires and is revoked

A caller who is not authorized, or an environment whose license is not valid, gets a response with Success = false and ErrorCode AccessDenied or LicenseNotValid; the request is not provisioned.

{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"IpAddress": "203.0.113.42",
"DurationHours": 8
}
}

revokeAccess​

Revokes every active grant the calling administrator holds (drops each database user and firewall rule, marks the audit row Revoked and clears its stored password). Idempotent and safe to call when no grant exists; never returns a password. A revoke that fails is never recorded as Revoked, because the database user may still exist: the grant stays Active with its expiry moved to now, a warning is raised, the response answers Success = false with ErrorCode TransientRuntime, and the expiry sweep retries the revoke and marks the grant Expired. Every other failure carries an ErrorCode too: AccessDenied (the caller is not a database access administrator), TransientRuntime, BusinessRule or UnexpectedError. revokeAccess is never refused because of the license.

Request Contract: MGCLatticeDbAccessRevokeRequestContract

FieldJSON KeyTypeRequiredDescription
Correlation IDCorrelationIdstring (GUID)NoEchoed on the response
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
}

The grant lifecycle is completed by MGCLatticeDbAccessExpiryBatch (action menu item MGCLatticeDbAccessExpiry), which revokes every active grant past its expiry, including grants whose revoke failed, marks them Expired and clears their stored password. There is no permanent recurring job: before a grant is issued, MGCLatticeDbAccessExpiryBatch::ensureScheduled schedules a one-time runtime sweep for the grant's expiry unless a sweep owned by an enabled user already starts by then, and the request fails if it cannot. A deferred revoke schedules a sweep for now. Each sweep schedules the next one only while active grants remain (at the earliest remaining expiry, or 15 minutes later when a revoke failed), so the sweep stops by itself when no grant is active. A sweep owned by a user who has since been disabled does not count as scheduled, so the next grant or revoke schedules one under an enabled user. See Background processes. The same provisioning core also backs the Database access grants page (Request access / Show password / Revoke for an authorized administrator). Show password decrypts the stored password only for an active grant that is not past its expiry and only for the user who requested it; a grant another administrator requested is refused (ErrorCode AccessDenied). Revoke works on any grant. Failures are recorded in telemetry (Lattice.DbAccess.RevokeDeferred, Lattice.DbAccess.RollbackFailed) with the grant's user name or record id only.


30. Posting Preview​

A posting preview validates a request without posting anything. Preview is opt-in per call via PreviewMode on the request (see Common Request Fields); results come back in the preview response block. A preview takes no idempotency claim, consumes no number sequence and is not license-gated.

Every write operation accepts PreviewMode. The operations that implement a preview run it at ValidationOnly fidelity: GL postGeneralJournal and postIntercompanyJournal; sales confirmSalesOrder, postSalesPackingSlip and invoiceSalesOrder (the operation sections list any other). Every other operation refuses PreviewMode: true with Success = false and ErrorCode PreviewUnsupported (PreviewMode true on the response) before it reads or writes anything.

Security: a preview is the posting operation called with PreviewMode, so it needs that operation's own privilege; no separate privilege is checked. MGCLatticePostingPreviewExecute (privilege, bundled by MGCLatticePostingPreviewDuty) grants only Invoke on the read-only status queries getSalesOrderStatus and getJournalStatus.

MGCLatticePreviewFidelity (enum)​

ValueNumericDescription
None0The response is not a preview (every normal call)
ValidationOnly1The request was validated as a preview; nothing was posted
ArtifactTypePurpose
MGCLatticeIPreviewableRequestInterfaceImplemented by request contracts whose operation runs a preview; carries the PreviewMode member
MGCLatticeServiceCallLog.IsPreviewFieldMarks a call-log row as a preview invocation rather than a real post

After a preview the operation checks that it left no idempotency claim and no open transaction; a failed check sets PreviewApplied to false and adds a warning. Business events self-suppress during a preview.


31. Service Test Console and Interaction Logging​

Two operator/diagnostic capabilities for exercising and observing the custom services in-environment.

Service Test Console​

Invoke a Lattice service operation from a form, without an external client. Only operations of Lattice services can be run, and only by a user who holds a privilege granting the operation itself (the same check the service endpoint applies); anything else is refused with ErrorCode AccessDenied.

ArtifactTypePurpose
MGCLatticeServiceTestConsoleFormPick a service/operation, supply the request JSON, run it, and view the response; a PreviewMode toggle runs the call as a posting preview (with an execute warning)
MGCLatticeServiceTestRunnerClassReflection invoker (SysDictClass::callObject + FormJsonSerializer) that deserializes the request JSON, calls the operation, and serializes the response
MGCLatticeServiceTestRequest / MGCLatticeServiceTestResultTables / contractsSaved requests and captured results

The console is privilege-gated by a dedicated duty/privilege. File ingestion invokes operations through the same runner, so the batch account that runs ingestion needs the privileges of the operations on a connection's allow-list.

Interaction logging​

Per-operation control over how much call-log detail is persisted.

MGCLatticeServiceLoggingLevel (enum)​

ValueNumericDescription
All0Persist a call-log row for every call
ErrorsOnly1Persist a row only when the call fails
Off2Persist nothing for this operation
ArtifactTypePurpose
MGCLatticeServiceOperationLogConfigTablePer-operation logging level (service + operation → level); the operation is the recorded operation name (see 24. OData Monitoring Entities)
MGCLatticeServiceLoggingPolicyClassResolves the effective level and gates call-log persistence in MGCLatticeOrderPostingServiceBase.recordCompletion
MGCLatticeServiceCallStatisticsTableAggregated per-operation call counts, timings, and failure counts
MGCLatticeServiceCallStatisticsRollupClass (RunBaseBatch)Rolls MGCLatticeServiceCallLog rows up into the statistics table; surfaced by an inquiry form

Per-operation retention is honored by MGCLatticeServiceLogCleanup (see 23. Process Automation).


32. Integration Dead-Letter Queue​

Failed integration work (async operations and file-ingestion segments) is captured in an operations-console dead-letter queue (DLQ) for auto-retry, manual fix-and-resubmit, or parking.

ArtifactTypePurpose
MGCLatticeIntegrationDeadLetterTableOne row per failed source (unique on SourceType + SourceRefId): the dead-letter id DeadLetterId (a GUID), source type and reference, target service and operation, the RequestId (the RequestId inside the payload, a GUID), the LegalEntityId of the failed work, the stored request payload, an optional operator EditedPayload, error code and category, status, retry bookkeeping, LastActionedBy and the modified date and user
MGCLatticeIntegrationDlqManagerClassenqueue (record a failure), replay (re-invoke from the stored payload), resubmit (manual fix-and-resubmit, below), closeCompletedRequeued and computeBackoff (exponential backoff for the auto-retry batch)
MGCLatticeIntegrationDlqRetryBatchBatch classAuto-retry sweep (below)
MGCLatticeIntegrationDlqEditReplayFormEdit the payload of a dead-letter row and resubmit it
MGCLatticeIntegrationDlqStatus / MGCLatticeIntegrationDlqSourceEnumsRow status (Retrying 1, Parked 2, Reprocessed 3, Discarded 4, Held 5, Requeued 6) and originating subsystem (AsyncOperation, FileIngestion)

Source reference. For an async operation SourceRefId is the tracking ID as plain GUID text (lower case, no braces) and ServiceName/OperationName are the target operation. For a file-ingestion record SourceRefId is the segment's record id, ServiceName is the connection and OperationName the segment operation, and RequestId is empty. RequestId joins the dead letter to LatticeServiceCallLogs and LatticeServiceIdempotencyLogs.

Enqueue policy: a retryable failure is enqueued Retrying with NextRetryDateTimeUtc = now (the retry batch picks it up); a terminal failure is Parked for manual review only, and a parked row raises the MGCLatticeIntegrationFailureBusinessEvent business event when the event is activated (the only alert channel; subscribe a Power Automate flow to send e-mail). When a source fails again after its row was closed (Reprocessed, Discarded) or re-queued (Requeued), the same row is re-opened - Retrying or Parked again, attempt count increased, failure details refreshed, park alert raised - so a second failure is never lost. A row that is still open (Retrying, Parked, Held) only gets the latest failure details.

Auto-retry - MGCLatticeIntegrationDlqRetryBatch: runs every 5 minutes as the Lattice dead-letter retry background process, which creates a batch job only when a row is due or re-queued. Each run closes Requeued file-ingestion rows whose segment has been processed since (Reprocessed), recovers async operations left Processing by a dead task (see 23. Process Automation), then replays every Retrying row that is due. A successful async replay is Reprocessed; a successful file-ingestion replay only re-queues the segment, so the row becomes Requeued until the segment is processed (closed as Reprocessed) or fails again (re-opened). A failed replay is rescheduled with exponential backoff, or Parked once MaxAttempts is reached.

Fix-and-resubmit - MGCLatticeIntegrationDlqManager.resubmit(deadLetterId): replays a row now using its effective payload - the operator-edited payload when one was supplied via MGCLatticeIntegrationDlqEditReplay, otherwise the original (clearing an edit therefore restores the original) - then records the outcome: Reprocessed for an async row, Requeued for a file-ingestion row, or Parked on failure. Only an open row (Retrying, Parked, Held) can be resubmitted: a Reprocessed, Discarded or Requeued row is refused, so an old item whose idempotency claim was already purged can never be posted again from the queue. Resubmitting requires the dead-letter manage entry point (the same check as the console actions). Replay safety (idempotency): replay re-invokes with the RequestId inside the payload, so a previously succeeded request returns the cached response (no second post) while a genuinely failed request (whose claim row was deleted) re-executes - with the edit applied.

Console actions. Retry now (not for Reprocessed, Discarded or Requeued rows), Hold, Release and Discard stamp the acting user in LastActionedBy and record a Lattice.Dlq.ActionTaken telemetry event; the row's modified date and user record the change.

Replaying an async operation re-checks the async operation registry and requires the replaying user (an operator resubmitting, or the owner of the Lattice dead-letter retry background process, by default the user the database synchronization ran as) to have access to the target service operation, as for a direct call; otherwise the replay is refused. A successful replay also sets the original async operation's tracking record to Succeeded with the document and posted document number, so getAsyncOperationStatus reports the outcome. Replaying a file-ingestion segment puts the segment back to Queued with its attempt counter reset, so the segment processor renders and dispatches it again on its next run.


33. Inbound Order Guardrail Policy​

A parameter-driven policy layer that governs inbound (integration-created) sales orders before they flow downstream. It is self-contained - a per-order state table rather than a SalesTable field extension - and inert until enabled.

MGCLatticeInboundOrderPolicyStatus (enum)​

ValueNumericDescription
Pending0Marked on insert; awaiting evaluation
Held1Price outside tolerance and the standard price hold (HoldCode) is on the order; waits for that hold to be cleared
AutoConfirmed2Confirmed automatically by the policy
Processed3Evaluation complete, left for the user
Released4The standard price hold was cleared or removed; awaiting the next evaluation run
Flagged5Price outside tolerance but no standard hold was placed (no PriceHoldCode, or the feature off); not auto-confirmed, not evaluated again
ArtifactTypePurpose
MGCLatticeInboundOrderPolicyParametersTable (one row per legal entity) + formMaster switch PolicyEnabled (default Off), price-tolerance percent, and related settings
MGCLatticeInboundOrderPolicyStateTablePer-order guardrail state (MGCLatticeInboundOrderPolicyStatus), the hold reason, the standard hold code the policy placed (HoldCode, empty when none) and the post-confirm edit-lock timestamp, keyed by SalesId; deleted with its sales order (SalesTable Deleted handler), so a reused order number is evaluated as a new order
MGCLatticeInboundOrderGuardrailPolicyClassThe evaluation engine
MGCLatticeInboundOrderPolicyEvaluationBatchClass (RunBaseBatch) + menu itemEvaluates Pending orders and takes Released orders on, out of band (the heavy confirm must not run in the order-creation or hold-clearing transaction)
SalesTable / SalesLine event handlersData event handlersMark new orders Pending on insert; enforce the post-confirm edit-lock via validating-write/-delete
MGCLatticeMCRHoldCodeTrans_Table_ExtensionTable CoC (MCRHoldCodeTrans.update / delete)Moves a Held order to Released when its standard price hold is cleared or removed

Three safeguards, all gated by PolicyEnabled: (1) price-tolerance hold: a line whose SalesPrice deviates from the item base price beyond the configured tolerance keeps the order from being auto-confirmed (Held or Flagged, below); (2) auto-confirm: a hold-free, unconfirmed order with lines is confirmed via MGCLatticeSalesOrderPostingService.confirmSalesOrder; (3) post-confirm edit-lock: once confirmed, edits and deletes are blocked until the stamped time.

Held, released, flagged. When PriceHoldCode is set and the standard Advanced Order Hold status change feature is enabled, an order outside the tolerance gets that standard order hold (MCRHoldCodeTrans) and becomes Held with HoldCode set. Clearing that hold (the Order holds page, call center, or any code that clears it through MCRHoldCodeTrans.update), or deleting it, moves the order to Released in the same transaction; clearing a different hold does not, nor does clearing one of two active holds of the same code. The next evaluation run takes a Released order on without checking the price again: with AutoConfirmEnabled, no other active standard hold and a confirmable order, it is confirmed and edit-locked (AutoConfirmed), otherwise it becomes Processed. HoldReason and HoldCode are kept. When no standard hold is placed (no PriceHoldCode, the feature off, or the placement failed), the order becomes Flagged: nothing stops it, it is not auto-confirmed and not evaluated again. The Inbound orders on hold tile query (MGCLatticeInboundOrderPolicyStateHeld) counts Held rows only.


34. Recurring Data Job Configuration Entities​

Two writable entities expose the data management recurring data job - the schedule that moves messages into or out of a data project - so an integration can be configured over OData or imported through data management instead of being set up by hand with Create recurring data job on a data project in the Data management workspace.

EntityCollection NameBacking TableKeyDescription
MGCLatticeRecurringDataJobEntityLatticeRecurringDataJobsIntegrationActivityTableNameThe job: its data project, direction, schedule and state
MGCLatticeRecurringDataJobClientEntityLatticeRecurringDataJobClientsIntegrationClientMapTableJobName + ClientIdA client application authorized to submit messages to a job

Both are DataManagementEnabled with their own staging tables, IsPublic, entity category Configuration, and shared (not per-company). Security: MGCLatticeRecurringDataJob*EntityView in the MGCLatticeDataEntitiesView duty; ...EntityMaintain in the high-risk MGCLatticeIntegrationServiceHighRiskDuty, so only the administrator role can create, change or delete jobs and client authorizations. Through the entity, changing State (PATCH) and invoking the Activate and Deactivate actions both need Maintain recurring data jobs (MGCLatticeRecurringDataJobEntityMaintain), which grants Invoke on the two action methods.

The schedule is projected, not stored as given​

IntegrationActivityTable stores a schedule as a packed container, which no data entity can carry. The entity projects it into scalars and repacks it on write:

PropertyTypeNotes
RecurrenceUnitSysRecurrenceUnitMinute, Hour, Day, Week, Month, Year
RecurrenceIntervalintEvery N units
RecurrenceStartDateTimeUTC datetimeFirst run
RecurrenceEndTypeMGCLatticeRecurrenceEndTypeNotSet (0), NoEnd (1), EndAfterCount (2), EndByDate (3)
RecurrenceEndAfterCountintWith EndAfterCount
RecurrenceEndDatedateWith EndByDate
RecurrenceTimeZoneTimezoneThe zone the schedule's clock times are read in
MonitoringRecurrenceUnit, MonitoringRecurrenceIntervalThe monitoring job's schedule; hourly by default
RecurrenceDescriptionstring, read-onlyThe recurrence rendered as the platform renders it
BatchGroupIdstringNot persisted on the job: the batch group used when it is activated

A repack starts from the stored container, so pattern detail the projection does not express - a weekly job's weekday, a monthly job's day - survives an edit that does not change the unit.

State is an operation​

State is not a plain column. A write that moves it from Inactive to Active runs the platform scheduler (IntegrationPacker::PackActivity → SysIntegrationSchedulerService.Start), the same call the setup page makes; a write back to Inactive stops the job's batch jobs. Activation is refused, naming the reason, unless the job has a recurrence and at least one enabled client application.

A job is always created inactive - the client authorizations it needs cannot exist before it does - so creation and activation are two writes.

The same operations are bound OData actions, granted by the same privilege as writing State (MGCLatticeRecurringDataJobEntityMaintain), so the Integration administrator role can use either.

ActionParametersReturns
Activate_batchGroupId (string, blank for the default batch group)A sentence describing the outcome
DeactivatenoneA sentence describing the outcome
POST {baseUrl}/data/LatticeRecurringDataJobs(Name='NightlyCustomerImport')/Microsoft.Dynamics.DataEntities.Activate
Content-Type: application/json

{ "_batchGroupId": "" }

Constraints worth knowing​

ConstraintBehavior
The data project must already existThe platform validates the relation: the value '…' in field 'Processing group' is not found in the related table 'Definition Groups'. Neither entity creates data projects.
A running job's schedule cannot be changedThe platform refuses it. The entity only writes the recurrence when it differs from what is stored, so editing other properties of a running job still works.
ActivityId is read-onlyAssigned by the platform. Name is the key.
A job name with { or } cannot be activatedThe platform's scheduler fails on such a name. Choose job names without braces.
Row-by-row processingActivation happens in the row write path, so set-based processing must stay disabled for these entities.
JobName on the client entityA computed column resolving the stored record id to the job's name, so it can be filtered and exported; on write it is resolved back, and a name matching no job fails the row.

Operator procedures, including the import order, are in Data entities. How each job is doing, and its messages, are in 37. Recurring Data Job Health Entities.


35. Data Management Configuration as Code​

Integration configuration - which data projects exist, what entities they carry, which recurring data jobs run them and on what schedule - is normally built by hand in each environment and rebuilt after every database copy. MGCLatticeDmfConfigService makes it a file: capture it once, commit it, and have a pipeline apply it to every environment.

Service group: MGCLatticeDataManagementServiceGroup · Service: MGCLatticeDmfConfigService

OperationPurposePrivilege
captureSpecReads an environment's data projects and recurring data jobs as a specificationMGCLatticeDmfConfigServiceView
specFromPackageManifestTurns a data package's Manifest.xml into a specificationMGCLatticeDmfConfigServiceView
diffSpecCompares a specification with the environment, member by member, without changing itMGCLatticeDmfConfigServiceView
applySpecMakes an environment match a specificationMGCLatticeDmfConfigServiceApply

...View sits in MGCLatticeIntegrationServiceOperationsDuty rather than the read-only query duty, because a captured specification exposes an environment's integration configuration; ...Apply sits in MGCLatticeIntegrationServiceHighRiskDuty, because applying a specification changes integration configuration and can start and stop jobs.

The specification​

{
"SpecVersion": "1.1",
"Description": "Nightly customer feed",
"DataProjects": [
{
"Name": "NightlyCustomerImport",
"Description": "Customers from the CRM",
"OperationType": "Import",
"TruncateEntityData": false,
"Entities": [
{
"EntityName": "Customers",
"SourceFormat": "CSV-Unicode",
"ExecutionUnit": 1,
"LevelInExecutionUnit": 1,
"SequenceInLevel": 1,
"RunBusinessLogic": true,
"RunBusinessValidation": true
}
]
}
],
"RecurringDataJobs": [
{
"Name": "NightlyCustomerImport",
"DataProjectName": "NightlyCustomerImport",
"Direction": "Inbound",
"RecurrenceUnit": "Hour",
"RecurrenceInterval": 4,
"RecurrenceStartDateTime": "2026-10-01T07:00:00Z",
"RecurrenceEndType": "NoEnd",
"MonitoringRecurrenceUnit": "Hour",
"MonitoringRecurrenceInterval": 1,
"UseDataAreaIdFromMessage": true,
"Activate": true,
"Clients": [
{ "ClientId": "00000000-0000-0000-0000-000000000000", "IsEnabled": true }
]
}
]
}

Enumerations that describe the configuration travel as element names - "Import", "Hour", "NoEnd" - never as integers and never as labels, so a specification written on one environment applies on another whatever language it runs in. An unrecognised name fails the item and the error lists the names that would have worked. The yes/no switches (GenerateDataPackage, TruncateEntityData, RunBusinessLogic, RunBusinessValidation, SkipStaging, Disable, FailLevelOnError, ProcessMessagesSerially, UseDataAreaIdFromMessage, PreventUpload, Activate, IsEnabled) are JSON booleans, true or false, like the request's ValidateOnly and PruneMissing, and captureSpec writes them the same way.

The one exception is RecurrenceTimeZone, which is the zone's number written as a string ("89" is UTC). Timezone is a kernel enumeration with no element names: asked for the name of a value the platform answers with a localised label, which is exactly what a committed file must not contain. Leave it out and the environment's own preferred time zone is used, which is usually what you want.

ClientId is environment-specific. The Entra application that calls the recurring integrations endpoints normally differs per environment, so supply it from the pipeline rather than committing it.

Field mappings​

Each entity line can carry a Mapping. Leave it out and the line uses the mapping data management generates for it, which keeps following the entity when fields are added to it.

"Mapping": {
"Mode": "DefaultWithOverrides",
"Overrides": [
{ "StagingField": "ISSALESTAXINCLUDEDINPRICE", "UseEnumLabel": true },
{ "StagingField": "DESCRIPTION", "TextQualifier": true }
],
"SourceFields": [],
"Conversions": [],
"Transforms": []
}
MemberMeaning
ModeDefault (the generated mapping), DefaultWithOverrides (the generated mapping, with Overrides replacing the rows of the staging fields they name) or Explicit (Overrides is the whole mapping). A Default mapping cannot have overrides.
OverridesMapping rows: SourceField, StagingField, AutoDefault, DefaultValue, UseEnumLabel, IsAutoGenerated, TextQualifier, DefaultValueEqualsNull, ArrayIndex. An override names a staging field and replaces every generated row for it. An override that replaces one generated row keeps that row's source field when it leaves SourceField blank; the switches it leaves out are off.
SourceFieldsThe source format: the columns a delimited file is read by, in order (Name; Type, Size, Position, Mandatory, Disabled as captured). Listed, the line's source format becomes exactly those columns in that order, generated the way Generate source mapping does from a sample file, and the generated rows follow them. Empty means the generated source format, except in Explicit mode, where the source format is the rows' source fields in row order, so a mapping that lists three columns accepts a file with those three columns.
ConversionsValue conversions: StagingField, SourceField, FieldType, From, To.
TransformsThe line's XSLT transforms in order, as the file references the environment stores.

Mode is an element name, and the switches (AutoDefault, UseEnumLabel, IsAutoGenerated, TextQualifier, DefaultValueEqualsNull, Mandatory, Disabled) are JSON booleans, like the rest of the specification. DefaultValue is text; an enumeration's default is written as its number.

Data management reads a delimited file by the positions of the source format, so the source format must match the files a sender sends. The generated source format has a column for every entity field; give a recurring import line the sender's columns in SourceFields, or map it Explicit.

captureSpec writes each line's mapping the shortest way that reads back exactly: Default when it is the generated mapping, otherwise only the rows that differ, or Explicit when the line no longer maps a field the generated mapping has. A line whose source format differs from the generated one lists its SourceFields. A version 1.0 specification still applies. It has no Mapping members, so its lines use the generated mapping.

What applySpec can write. Applying a mapping regenerates the line and saves the overrides the way the mapping page does. A line created by applySpec gets the generated mapping, and an existing line with no mapping at all is regenerated (Updated, detail Mapping). Data management offers no programmatic way to write a default value, a value conversion, a transform, or a source field's type, size, mandatory or disabled setting other than what generation gives it, and rewriting a mapping deletes the line's default values and conversions. captureSpec and diffSpec show them; applySpec fails a line whose specification would need one of them written, names them, and changes nothing on that line. Set those on the target environment's mapping page; once they match, the line reports Unchanged.

Applying​

POST {baseUrl}/api/services/MGCLatticeDataManagementServiceGroup/MGCLatticeDmfConfigService/applySpec
Content-Type: application/json

{ "_request": { "Spec": { …the committed file… }, "ValidateOnly": false, "PruneMissing": false } }

The response reports every item:

{
"Success": true,
"ValidateOnly": false,
"Created": 0, "Updated": 1, "Unchanged": 3, "Removed": 0, "Failed": 0,
"Message": "Applied: 0 created, 1 updated, 3 unchanged, 0 removed, 0 failed.",
"Items": [
{ "Kind": "DataProject", "Name": "NightlyCustomerImport", "Outcome": "Unchanged", "Detail": "" },
{ "Kind": "RecurringDataJob", "Name": "NightlyCustomerImport", "Outcome": "Updated", "Detail": "schedule" }
]
}
FlagEffect
ValidateOnlyWorks out what would change and writes nothing. The plan step for a pull request.
PruneMissingAlso removes entity lines and client authorizations the specification does not describe. Off by default, because an environment usually hosts more than one integration.

What makes it safe to run on every deployment​

It is idempotent. A second run against an unchanged environment reports every item Unchanged and changes nothing - so Created + Updated + Removed is a usable drift signal, not just noise. A pipeline can fail a post-deployment check when it is non-zero.

It reconciles rather than replays. Each item is compared and written only where it differs, and the result says what differed ("Detail": "schedule"). Nothing is deleted unless PruneMissing asks for it.

A running job is stopped before its schedule changes, and started again afterwards if the specification says it should be running. The platform refuses to change the recurrence of an active job; an operator applying a changed schedule should not have to know that.

Order is dependency order - projects, then their lines, then jobs, then clients, then activation - so a specification applies to a completely empty environment in one call.

Failures are per item. There is no outer transaction: activation creates batch jobs, and a specification that fails half way is recovered by fixing it and re-applying, which is safe precisely because the apply is idempotent. Success is false when any item failed, and the failing items say why. A request without a body or without a Spec answers Success false with a Message and no items.

Do not call the applier from inside a transaction. X++ rethrows an exception caught inside one, so the per-item error handling would not fire. The service operation is not in a transaction; a caller writing X++ should not put it in one either.

Comparing (diffSpec)​

diffSpec answers how does this environment differ from the file? member by member, without changing anything: the check for a pull request or a drift report.

POST {baseUrl}/api/services/MGCLatticeDataManagementServiceGroup/MGCLatticeDmfConfigService/diffSpec
Content-Type: application/json

{ "_request": { "Spec": { …a specification… }, "PruneMissing": false } }
{
"Success": true,
"Differences": 1, "NotApplicable": 0,
"Message": "1 differences found; 0 of them cannot be applied.",
"Items": [
{ "Kind": "ProjectEntity", "Name": "NightlyCustomerImport / Customer groups",
"Member": "Mapping.Overrides[DESCRIPTION].TextQualifier",
"EnvironmentValue": "false", "SpecificationValue": "true", "CanApply": true, "Note": "" }
]
}
MemberMeaning
DifferencesHow many differences were found. Zero means the environment matches the specification.
NotApplicableHow many of them applySpec cannot remove.
ItemsOne per difference: Kind (DataProject, ProjectEntity, RecurringDataJob or JobClient) and Name of the item, the Member that differs, EnvironmentValue, SpecificationValue, CanApply and a Note.

It uses the same comparison as applySpec with ValidateOnly, so the two always agree. An item the environment does not have is one difference with a blank Member. With PruneMissing on, the entity lines and client authorizations the specification does not describe are reported too, as an apply with PruneMissing would remove them. CanApply is false for a difference applySpec cannot remove, such as a default value or a conversion, with the reason in Note. A differing environment is still a successful comparison: Success is false only when the comparison could not be made, for example with no request, no specification or a specification version this build does not read.

Comparing a mapping needs the generated mapping, which data management only produces inside a data project: captureSpec and diffSpec create a temporary data project named MGCLatticeMapDefault-…, read the generated mapping from it and remove it again. That project is the only thing either operation writes, and captureSpec never captures it. If one is ever left behind, it is safe to delete.

From a data package​

An integration that already exists as a data package does not have to be rebuilt by hand:

POST {baseUrl}/api/services/MGCLatticeDataManagementServiceGroup/MGCLatticeDmfConfigService/specFromPackageManifest
Content-Type: application/json

{ "_manifestXml": "…the contents of the package's Manifest.xml…", "_projectName": "" }

The manifest is read with the platform's own contract type, so any manifest a real package export produces is understood, and it yields the project and all its entity lines - execution units, levels, sequences and source formats included. A package's Manifest.xml also carries each entity's field mapping, default values, conversions and transforms; they come back in the line's Mapping as Explicit. What comes back is a specification to commit.

Constraints worth knowing​

ConstraintBehavior
An entity line can only name an entity in the data management entity listOtherwise that line fails, naming the entity. After deploying new entities, refresh the entity list.
EntityName is the data management display nameCustomers, not CustCustomerV3Entity.
A data project name is capped at 60 characters, a job name at 40A longer name is refused up front rather than stored truncated, which would make the specification differ from the environment for ever.
Client authorizations are deleted through the table, not the entityThe platform declares IntegrationActivityTable.ClientIdMapRelation with OnDelete Restricted pointing at the client map, so an entity delete is refused with a message naming the restriction in the opposite direction to the data. The platform's own cascade removes these rows the same way.
Default values, value conversions, transforms and source field types and sizes are not writtenThey are captured and compared, but applySpec fails the line that would need one written (see Field mappings). Set them on the mapping page.
The generated mapping follows the company the call runs inA staging field that applies only to some countries or regions can be generated in one company and not in another. Capture, compare and apply in companies of the same country or region.

36. Data Management Field Mapping Service​

A data project's field mappings drift: an update adds fields to an entity after its mapping was generated, an entity loses a field a mapping still points at, or a line ends up with no mapping at all. The import then fails or silently skips data. MGCLatticeDmfMappingService finds those problems before a run does, and repairs them without touching what was customized.

Service group: MGCLatticeDataManagementServiceGroup · Service: MGCLatticeDmfMappingService

OperationPurposePrivilege
validateMappingsChecks the field mappings of data projects and reports every problem. Read-only.MGCLatticeDmfMappingServiceView (operations duty)
refreshMappingsAdds missing mappings, removes mappings to fields that no longer exist and, on request, regenerates a stale staging-to-target mappingMGCLatticeDmfMappingServiceMaintain (high-risk duty)

Both take the request in _request, without the common envelope, and are not license-gated. Every refusal and unexpected error comes back as a result with Success false and a Message, never as a service fault.

validateMappings​

POST {baseUrl}/api/services/MGCLatticeDataManagementServiceGroup/MGCLatticeDmfMappingService/validateMappings
Content-Type: application/json

{ "_request": { "DataProjectNamePattern": "Cust*", "RecurringDataJobName": "" } }
Request memberTypeMeaning
DataProjectNamePatternstringData projects to check, as a pattern (Cust*, or * for every project).
RecurringDataJobNamestringA recurring data job; its data project is checked.

At least one is required; a project named by both is checked once. A pattern that matches nothing, or an unknown job, is refused rather than reported clean, so a typo cannot pass a pipeline gate. Every enabled, non-composite entity line of each project is checked.

{
"Success": true,
"Message": "Checked 1 data projects and 2 entities: 0 errors, 1 warnings.",
"ProjectsChecked": 1, "EntitiesChecked": 2, "Errors": 0, "Warnings": 1,
"Findings": [
{ "DataProject": "CustomerImport", "Entity": "Customer groups", "Field": "DESCRIPTION",
"Check": "FieldNotMapped", "Severity": "Warning",
"Message": "Staging field 'DESCRIPTION' has no mapping. It may have been added to the entity after the mapping was generated.",
"SuggestedFix": "Run refreshMappings to add the default mapping for 'DESCRIPTION', or leave it unmapped on purpose." }
]
}

Success is true when the check ran and found no errors; warnings are allowed. Each finding carries DataProject, Entity, Field, Check, Severity (Error or Warning), Message and SuggestedFix.

CheckSeverityMeaning
ProjectNotFoundErrorThe data project does not exist (for example a recurring data job pointing at a deleted project).
NoMappingErrorThe entity has no source-to-staging mapping at all.
KeyFieldUnmappedErrorA mandatory key field of the staging table is neither mapped from a source field nor auto-generated.
MandatoryFieldUnmappedError(Import projects) a mandatory staging field is neither mapped, defaulted nor auto-generated.
StagingFieldMissingErrorA mapping points at a staging field that no longer exists.
SourceFieldMissingError(File sources) a mapping reads a source field that is not one of the entity's source fields.
FieldNotMappedWarningA staging field the standard mapping generation maps has no mapping, typically a field added to the entity after the mapping was generated.
TargetMappingStaleWarningThe entity's staging-to-target mapping lacks a field, or maps a staging or entity field that no longer exists. It is shared by every project that uses the entity.

refreshMappings​

POST {baseUrl}/api/services/MGCLatticeDataManagementServiceGroup/MGCLatticeDmfMappingService/refreshMappings
Content-Type: application/json

{ "_request": { "DataProjectName": "CustomerImport", "EntityName": "", "RegenerateTargetMapping": false, "ValidateOnly": true } }
Request memberTypeMeaning
DataProjectNamestringRequired. The data project.
EntityNamestringOne entity of the project, by its data management name; blank for every enabled entity.
RegenerateTargetMappingbooleanAlso regenerate the staging-to-target mapping of each entity whose mapping is stale. This changes it for every project that uses the entity.
ValidateOnlybooleanList the changes without making them.

Per entity, the refresh:

  • keeps every existing mapping exactly as it is: custom source fields, default values, auto-generated fields, text qualifier and blank-value settings;
  • adds the standard default mapping for each staging field that has none;
  • removes mappings to staging fields that no longer exist, with their value conversions;
  • with RegenerateTargetMapping, regenerates a stale staging-to-target mapping.

The mapping rows of each entity change in one transaction, completely or not at all. A preview lists exactly the changes the real run makes, and a second run changes nothing. A field that only becomes mappable through the regenerated staging-to-target mapping is added by the next refresh; validateMappings reports it in between.

{
"Success": true, "ValidateOnly": true,
"Message": "Previewed: 1 mappings added, 0 removed, 12 kept, 0 staging-to-target mappings regenerated, 0 failed.",
"Added": 1, "Removed": 0, "Kept": 12, "TargetRegenerated": 0, "Failed": 0,
"Changes": [
{ "DataProject": "CustomerImport", "Entity": "Customer groups", "Field": "DESCRIPTION",
"SourceField": "DESCRIPTION", "Change": "Added", "Detail": "Mapped from the existing source field 'DESCRIPTION'." }
]
}

Each change carries DataProject, Entity, Field (the staging field), SourceField, Change (Added, Removed, TargetRegenerated or Failed) and Detail. Success is false when the request was refused or a change failed.

Refusals (Success false, nothing changed): no request, no data project name, an unknown data project, or an entity the project does not have (or a composite entity).

The refresh cannot write a single mapping row the way you would on the mapping page; to map a source column to a field that replaced a removed one, use the entity's mapping page. A walkthrough is in Validate and refresh data project mappings.


37. Recurring Data Job Health Entities​

Two entities show how each recurring data job is doing, so a monitor, a pipeline or a support tool can read it over OData instead of opening each job.

EntityCollection NameSingleKeyAccess
MGCLatticeRecurringJobHealthEntityLatticeRecurringJobHealthsLatticeRecurringJobHealthJobNameRead; write the thresholds and alert switch; actions Refresh, RefreshAll
MGCLatticeRecurringJobMessageEntityLatticeRecurringJobMessagesLatticeRecurringJobMessageMessageIdRead-only

Both are public and shared (no dataAreaId). Security: MGCLatticeRecurringJobHealthEntityView and MGCLatticeRecurringJobMessageEntityView in the MGCLatticeDataEntitiesView duty; MGCLatticeRecurringJobHealthEntityMaintain (thresholds and the two actions) in MGCLatticeDataEntitiesMaintain.

Recurring data job health (LatticeRecurringJobHealths)​

One row per recurring data job: its health, the reasons, the signal values the health was derived from, and the job's health thresholds. Enabled for data management, so the thresholds travel with the configuration, matched by job name.

MemberWritableMeaning
JobNameOn createThe recurring data job (must exist).
ActivityId, JobDescription, Direction, JobState, DataProjectNameNoFrom the job.
WindowHoursYesFailure window in hours; 0 = 24.
BacklogAgeMinutesYesHow long the oldest waiting message may wait; 0 = three recurrence intervals, at least 15 minutes.
SilenceMinutesYesHow long an active job may go without a message; 0 = off.
StuckMinutesYesHow long a message may stay in processing; 0 = 60.
FailureThresholdYesFailed messages that make the job Failing (and partially processed messages that give a warning); 0 = 1.
AlertsEnabledYesRaise the Recurring data job health changed business event for this job.
HealthStateNoInactive, Healthy, Warning, Failing or Broken.
PreviousHealthState, StateChangedDateTimeNoThe state before the last change, and when it changed.
EvaluatedDateTime, ReasonsNoWhen the health was evaluated; one reason per line, worst first.
BacklogCount, OldestBacklogDateTimeNoMessages waiting (import: enqueued; export: not acknowledged) and since when.
FailedMessageCount, PartialExecutionCountNoFailed messages, and messages processed with failed rows, in the failure window.
LastMessageDateTime, StuckMessageCount, EnabledClientCount, MappingErrorCountNoThe newest message, messages processing for longer than the stuck threshold, client applications allowed to submit, and mapping errors on the data project (as validateMappings counts them).
ProcessingBatchJobId, ProcessingBatchJobStatus, MonitoringBatchJobId, MonitoringBatchJobStatusNoThe job's batch jobs (0 = missing).

Health rules (the worst that applies wins):

StateWhen
BrokenAn active job whose batch jobs are missing or stopped (Withhold, Error, Ended, Canceling, Canceled), an active import job no client application may submit to, or mapping errors on its data project.
FailingFailed messages in the window reach the failure threshold.
WarningWaiting messages older than the backlog age (or any waiting message on an inactive job), messages processed with failed rows, messages processing for longer than the stuck threshold, or no message within the silence period.
HealthyAn active job no rule flags.
InactiveThe job is off and nothing waits.

Actions:

ActionBound toReturns
RefreshA rowEvaluates that job now and returns its health state (for example "Healthy").
RefreshAllThe entity setEvaluates every job, creates rows for jobs without one and removes the rows of deleted jobs; returns how many jobs changed state.
POST {baseUrl}/data/LatticeRecurringJobHealths(JobName='NightlyCustomerImport')/Microsoft.Dynamics.DataEntities.Refresh
POST {baseUrl}/data/LatticeRecurringJobHealths/Microsoft.Dynamics.DataEntities.RefreshAll

Both raise the health-changed business event for jobs with alerts on, as the scheduled evaluation does (see 23. Process Automation). A row for an unknown job is refused, and a row cannot be deleted: there is one per job, kept by the evaluation.

Recurring data job messages (LatticeRecurringJobMessages)​

Read-only, one row per message of a recurring data job: MessageId, JobName, JobActivityId, Direction, EntityName, Status, EnqueuedDateTime, EnqueuedBy, ProcessingStartedDateTime, ProcessingCompletedDateTime, Company, RetryCount, ErrorDetails, ExternalCorrelationId, ExecutionId, ExecutionStatus, StagingErrorCount and TargetErrorCount (summed over the execution's entities). Use ExecutionId with the data management execution APIs (for example GetExecutionErrors) to find the failed rows.

Status is the platform enumeration IntegrationActivityMessageStatus; filter on it with the qualified syntax:

GET {baseUrl}/data/LatticeRecurringJobMessages?$filter=JobName eq 'NightlyCustomerImport' and Status eq Microsoft.Dynamics.DataEntities.IntegrationActivityMessageStatus'ProcessedWithErrors'

Error Response Patterns​

All services return consistent, predictable error responses. The following table documents common error patterns that callers should handle programmatically.

Null or Missing Request​

Occurs when the request payload is not provided.

{
"Success": false,
"Status": 4,
"Message": "Request payload is required.",
"Errors": ["Request payload is required."]
}

Empty RequestId​

Occurs when RequestId is omitted or set to an empty GUID.

{
"Success": false,
"Status": 4,
"ErrorCode": 1,
"Message": "RequestId is required.",
"Errors": ["RequestId is required."]
}

Unknown LegalEntityId​

Occurs when the LegalEntityId in the request names no legal entity the caller can access. The request may name any existing legal entity; the operation runs in that legal entity, whatever the caller's default company.

{
"Success": false,
"Status": 4,
"ErrorCode": 1,
"Message": "Legal entity XXXX was not found or is not accessible.",
"Errors": ["Legal entity XXXX was not found or is not accessible."]
}

Unexpected Error​

An exception that is not an error, CLR error, deadlock or update conflict returns the message Operation <name> failed due to an unexpected error. It is classified UnexpectedError, not retryable. The transaction is rolled back and the RequestId is released so it can be retried.

Duplicate RequestId (Claim-First Idempotency)​

Idempotency is claim-first: before executing any work, the service atomically inserts an in-progress claim row (status Processing) keyed on the unique RequestId index. That insert - not a preceding SELECT - is the concurrency gate, which closes the concurrent-duplicate double-post race in which two simultaneous submissions of the same RequestId could otherwise both create financial transactions. Exactly one submission wins the claim and executes; any concurrent or later submission with the same RequestId is resolved against the existing claim:

  1. Original succeeded → cached replay. On success the claim is finalized to Succeeded with the resulting DocumentId. A duplicate replays that cached outcome instead of re-executing. The replay carries Success=true, Status=Succeeded, ErrorCode=None, a freshly generated ExecutionId, replay timestamps for StartDateTimeUtc/EndDateTimeUtc (current UTC, not 1900-01-01), a DurationMs of 0, the original DocumentId/PostedDocumentId/CorrelationId, and an informational message noting it is a cached response.
  2. Original still in flight → not re-executed. While the first submission is still running, a duplicate is not executed a second time. It receives a non-success response classified ErrorCode=RequestInProgress with IsRetryable=true and Status=Processing - retry once the original completes.
  3. Original failed → retryable. On failure the claim row is deleted (failures are not cached), so resubmitting the same RequestId re-executes the operation. Transiently failed requests can therefore be safely retried.
  4. Stale claim → needs review. If a claim was left Processing for more than 60 minutes (its owning worker stopped before recording completion), a duplicate is not executed: it receives ErrorCode=RequestNeedsReview (not retryable), because the original may have posted. The reconciliation sweep or an operator (Mark succeeded or Release claim on the service idempotency log page) resolves the claim; then the request can be resubmitted.
  5. Another operation → refused. A RequestId belongs to the operation that first used it. Sending it to a different operation, of the same or another service, is refused with Success=false, ErrorCode=DuplicateRequest and IsRetryable=false, and the operation does not run: RequestId <id> was already used for operation <ServiceName>.<OperationName>. Send a new RequestId for this operation. Only a repeat of the same operation replays the cached result.

Every answer given without executing - a cached replay, an in-progress or needs-review answer, a DuplicateRequest refusal and a license refusal - is written to the service call log like an executed call; the claim itself is not changed.

Cached replay (original succeeded):

{
"Success": true,
"Status": 3,
"ErrorCode": 0,
"IsRetryable": false,
"Message": "Duplicate request detected. Original request processed at 2026-01-15T10:30:01.234Z.",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"ExecutionId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"DocumentId": "SO-000123",
"PostedDocumentId": "SO-000123-1",
"StartDateTimeUtc": "2026-01-16T08:00:00.000Z",
"EndDateTimeUtc": "2026-01-16T08:00:00.000Z",
"DurationMs": 0,
"Errors": [],
"InformationalMessages": ["This is a cached response from a previous execution of the same RequestId."]
}

Request already in progress (original still running):

{
"Success": false,
"Status": 2,
"ErrorCode": 8,
"IsRetryable": true,
"Message": "A request with the same RequestId is already being processed. Retry once it completes.",
"RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"DurationMs": 0,
"Errors": ["Duplicate request already in progress."]
}

Document Not Found​

Occurs when the target document does not exist in the specified legal entity.

{
"Success": false,
"Status": 4,
"Message": "Sales order SO-999999 was not found.",
"DocumentId": "",
"Errors": ["Sales order SO-999999 was not found."]
}

The message format follows the pattern: "{document type} {identifier} was not found." Examples include:

  • "Sales order SO-999999 was not found."
  • "Purchase order PO-999999 was not found."
  • "Production order P999999 was not found."

An unknown journal name ("Journal name INVALID was not found.") or fixed asset ("Fixed asset COMP-999999 was not found.") uses the same wording but is a request check: for example the general ledger journal post and the fixed asset acquisition and disposal return ValidationFailed for it. Only the general ledger journal preview answers an unknown journal name with DocumentNotFound.

Summary of Error Categories​

Each failure carries a machine-readable ErrorCode (see MGCLatticeServiceErrorCode) and an IsRetryable flag - route and decide retries on those, not on the localized Message/HTTP status.

CategoryErrorCodeHTTP StatusSuccessIsRetryableDescription
Validation errorValidationFailed200falsefalseBad input data (incl. empty RequestId). Fix the request and resubmit.
Unknown legal entityValidationFailed200falsefalseLegalEntityId names no accessible legal entity.
Document not foundDocumentNotFound200falsefalseReferenced document does not exist.
Invalid statusInvalidStatus200falsefalseDocument is in a state that does not allow the operation.
Business rule errorBusinessRule200falsefalseThe business processing failed after the request was accepted (for example D365 refused to create or post the document), or an unexpected exception occurred.
Dimension/account unresolvedDimensionValueNotFound200falsefalseA supplied financial dimension/account value could not be resolved.
Runtime/CLR errorTransientRuntime200falsetrueTransient infrastructure error. Retry with backoff.
Request in progressRequestInProgress200falsetrueAn identical RequestId is still executing. Retry once it completes.
RequestId used by another operationDuplicateRequest200falsefalseThe RequestId belongs to a different operation, of the same or another service. Send a new RequestId.
Earlier attempt needs reviewRequestNeedsReview200falsefalseAn earlier attempt with this RequestId stopped without a result. Check whether it posted before resubmitting.
Configuration missingConfigurationMissing200falsefalseSetup the operation needs (a number sequence, a chart of accounts) is missing.
License not validLicenseNotValid200falsetrueThe product license is not valid. Retry once it is renewed.
Platform throttling(n/a)429N/AtrueServer overloaded. Retry after Retry-After header value.