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
- Common Request Fields
- Common Response Format
- 1. Sales Order Posting Service
- 1a. Sales Order Capture Service
- 2. Purchase Order Posting Service
- 3. Transfer Order Posting Service
- 4. Inventory Journal Posting Service
- 4a. Inventory Cost Service
- 5. Production Order Posting Service
- 6. Return Order Services
- 7. Free Text Invoice Service
- 8. General Ledger Journal Service
- 8a. Journal Posting Service
- 9. Payment Journal Service
- 10. Workflow Action Service
- 11. Budget Register Service
- 12. Project Journal Service
- 13. Project Invoice Service
- 13a. Expense Report Service
- 14. Fixed Asset Service
- 15. Vendor Payment Proposal Service
- 16. Vendor Invoice Journal Service
- 16a. Vendor Invoice Service
- 17. Currency Revaluation Service
- 18. Purchase Requisition Service
- 19. Bulk Operations
- 20. Status Query Operations
- 21. Async Operations
- 22. Financial Dimension Support
- 23. Process Automation
- 24. OData Monitoring Entities
- 25. File Ingestion Framework
- 26. OData Entity Metadata Explorer
- 27. Price Inquiry Service
- 28. Sales Trade Agreement Service
- 29. Just-In-Time Database Access Service
- 30. Posting Preview
- 31. Service Test Console and Interaction Logging
- 32. Integration Dead-Letter Queue
- 33. Inbound Order Guardrail Policy
- 34. Recurring Data Job Configuration Entities
- 35. Data Management Configuration as Code
- 36. Data Management Field Mapping Service
- 37. Recurring Data Job Health Entities
- Rate Limiting and Throttling
- Error Response Patterns
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 Group | Services |
|---|---|
MGCLatticeAccountsReceivableServiceGroup | SalesOrderPosting, SalesOrderCapture (§1a), FreeTextInvoice, SalesReturn (§6), PriceInquiry (§27), SalesTradeAgreement (§28) |
MGCLatticeAccountsPayableServiceGroup | PurchaseOrderPosting, PurchaseReturn (§6), VendorInvoiceJournal, VendorInvoice (§16a), VendorPaymentProposal, PurchaseRequisition |
MGCLatticeInventoryServiceGroup | InventoryJournalPosting, TransferOrderPosting, InventoryCost (§4a) |
MGCLatticeProductionServiceGroup | ProductionOrderPosting |
MGCLatticeGeneralLedgerServiceGroup | GeneralLedgerJournal, PaymentJournal, BudgetRegister, CurrencyRevaluation |
MGCLatticeJournalPostingServiceGroup | JournalPosting (§8a) |
MGCLatticeFixedAssetsServiceGroup | FixedAsset |
MGCLatticeProjectServiceGroup | ProjectJournal, ProjectInvoice |
MGCLatticeExpenseServiceGroup | ExpenseReport (§13a) |
MGCLatticeWorkflowServiceGroup | WorkflowAction |
MGCLatticeAsyncOperationServiceGroup | AsyncOperation |
MGCLatticeDbAccessServiceGroup | DbAccess (§29) |
MGCLatticeDataManagementServiceGroup | DmfConfig (§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.
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Correlation ID | CorrelationId | string (GUID) | No | Caller-supplied identifier for distributed tracing. Echoed in the response. |
| Request ID | RequestId | string (GUID) | Yes | Unique identifier for this request. Must not be empty. |
| Legal Entity | LegalEntityId | string | Yes | Company/legal entity code (e.g., USMF). The operation runs in this legal entity, whatever the caller's default company; it must exist. |
| User Context | UserContext | string | No | Informational 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
PreviewModeboolean. Operations that implement a preview validate the request and post nothing when it istrue; every other operation refusesPreviewMode: truewithErrorCodePreviewUnsupportedbefore it reads or writes anything. See 30. Posting Preview.
Cross-reference keys. Request contracts that take a D365 id also accept an
ExternalSystemmember on the request header and an<Id>ExternalKeymember next to each id they cover (for exampleSalesOrderIdExternalKey, lineItemIdExternalKey). 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'sExternalSystem. 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 asValidationFailed(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
}
| Field | Type | Description |
|---|---|---|
Success | boolean | true if the operation completed without errors |
Status | enum MGCLatticeServiceCallStatus | Lifecycle status. Serialized as the enum's integer value (e.g. 3 = Succeeded, 4 = Failed, 2 = Processing). See MGCLatticeServiceCallStatus. |
ErrorCode | enum MGCLatticeServiceErrorCode | Machine-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. |
IsRetryable | boolean | true 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. |
Message | string | Human-readable result description |
CorrelationId | GUID | Echoed from the request |
ExecutionId | GUID | Server-generated unique ID for this execution |
RequestId | GUID | Echoed request identifier from the caller |
DocumentId | string | Primary document ID produced or affected by the operation (e.g., journal number, order number) |
PostedDocumentId | string | Number 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. |
StartDateTimeUtc | datetime | Server-side start time |
EndDateTimeUtc | datetime | Server-side completion time |
DurationMs | integer | Elapsed 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) |
Errors | string[] | Error messages. Populated only on failure (Success=false); includes captured D365 infolog error lines. Empty on success. |
Warnings | string[] | 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. |
InformationalMessages | string[] | 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.
| Field | Type | Description |
|---|---|---|
PreviewMode | boolean | true when the request asked for a preview (also on the PreviewUnsupported refusal of an operation without a preview) |
PreviewApplied | boolean | true 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. |
PreviewFidelity | enum MGCLatticePreviewFidelity | 0 = 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.
| Value | Numeric | Description |
|---|---|---|
None | 0 | Unset / default |
Processing | 2 | Execution in progress; also the status of a RequestInProgress answer |
Succeeded | 3 | Completed successfully |
Failed | 4 | Completed with errors |
PartialSuccess | 6 | Bulk 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.
| Value | Numeric | Retryable | Description |
|---|---|---|---|
None | 0 | - | No error (success) |
ValidationFailed | 1 | No | Request 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) |
DocumentNotFound | 2 | No | The referenced document/journal/asset does not exist in the legal entity |
InvalidStatus | 3 | No | The document is in a state that does not permit the requested operation |
BusinessRule | 4 | No | The business processing failed after the request was accepted, for example D365 refused to create or post the document |
DimensionValueNotFound | 5 | No | A supplied financial dimension/account value could not be resolved |
TransientRuntime | 6 | Yes | A CLR/runtime (infrastructure) fault was caught; safe to retry with backoff |
DuplicateRequest | 7 | No | The 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 |
RequestInProgress | 8 | Yes | An identical RequestId is currently being processed; retry once it completes (the request is not executed a second time) |
RequestNeedsReview | 9 | No | An earlier attempt with this RequestId stopped without a result and was not run again; check whether it posted before resubmitting |
PreviewUnsupported | 10 | No | The request asked for a posting preview of an operation that cannot be previewed |
ConfigurationMissing | 11 | No | Setup the operation needs is missing (for example a number sequence or a chart of accounts) |
LicenseNotValid | 12 | Yes | The product license is not valid; the request runs once the license is renewed |
UnexpectedError | 13 | No | An 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." |
AccessDenied | 14 | No | The 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) |
OperationDisabled | 15 | No | An 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).
| Value | Numeric | Error codes |
|---|---|---|
None | 0 | None only |
Connection | 1 | TransientRuntime |
Format | 2 | ValidationFailed, PreviewUnsupported |
Data | 3 | DocumentNotFound, InvalidStatus, BusinessRule, DimensionValueNotFound, DuplicateRequest, RequestInProgress, RequestNeedsReview, UnexpectedError |
Configuration | 4 | ConfigurationMissing, LicenseNotValid, AccessDenied, OperationDisabled |
MGCLatticeAsyncOperationStatus (enum)
Used by MGCLatticeAsyncOperationStatusContract.Status, MGCLatticeAsyncOperationResponseContract.Status, and the MGCLatticeAsyncOperationTracking table / MGCLatticeAsyncOperationTrackingEntity OData entity.
| Value | Numeric | Description |
|---|---|---|
None | 0 | Unset / default |
Queued | 1 | Submitted, awaiting batch pickup |
Processing | 2 | Running in the batch framework |
Succeeded | 3 | Completed successfully |
Failed | 4 | Completed with errors |
NotFound | 7 | No 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):
| Value | Numeric | Description |
|---|---|---|
Info | 0 | Informational message |
Warning | 1 | Non-fatal warning |
Error | 2 | Error 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Line Number | LineNum | decimal | One of LineNum / ItemId | The order line's line number |
| Item ID | ItemId | string | One of LineNum / ItemId | Item number; names the line when LineNum is not sent |
| Inventory Dimension ID | InventDimId | string | No | Narrows an ItemId match; must match the line when sent with LineNum |
| Quantity | Qty | decimal | Yes | Quantity to post, greater than zero |
| Selected | IsSelected | boolean | No | Defaults 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Sales Order ID | SalesOrderId | string | Yes | Sales order number (e.g., SO-000123) |
| Sales Order ID key | SalesOrderIdExternalKey | string | No | The sales order's alternate key in ExternalSystem, used in place of SalesOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Confirmation date. Defaults to system date. |
| Lines | Lines | MGCLatticeSalesPostingLineContract[] | No | The lines and quantities to post; omit to post the whole order (see Posting with lines) |
| Preview Mode | PreviewMode | boolean | No | true 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Sales Order ID | SalesOrderId | string | Yes | Sales order number |
| Sales Order ID key | SalesOrderIdExternalKey | string | No | The sales order's alternate key in ExternalSystem, used in place of SalesOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Packing slip date. Defaults to system date. |
| Lines | Lines | MGCLatticeSalesPostingLineContract[] | No | The lines and quantities to post; omit to post the whole order (see Posting with lines) |
| Preview Mode | PreviewMode | boolean | No | true 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Sales Order ID | SalesOrderId | string | Yes | Sales order number |
| Sales Order ID key | SalesOrderIdExternalKey | string | No | The sales order's alternate key in ExternalSystem, used in place of SalesOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Invoice date. Defaults to system date. |
| Lines | Lines | MGCLatticeSalesPostingLineContract[] | No | The lines and quantities to post; omit to post the whole order (see Posting with lines) |
| Preview Mode | PreviewMode | boolean | No | true 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Sales Order ID | SalesOrderId | string | Yes | Sales order number |
| Sales Order ID key | SalesOrderIdExternalKey | string | No | The sales order's alternate key in ExternalSystem, used in place of SalesOrderId. |
| External System | ExternalSystem | string | No | The 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 ID | PackingSlipId | string | No | The packing slip to cancel. Empty: the order's only packing slip that can be canceled |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Customer Account | CustAccount | string | Yes | Customer the order is for |
| Customer Account key | CustAccountExternalKey | string | No | The customer's alternate key in ExternalSystem, used in place of CustAccount. |
| External System | ExternalSystem | string | No | The 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 Code | CurrencyCode | string | No | Order currency; the customer's currency when empty |
| Sales Order ID | SalesOrderId | string | No | Order number to use; the number sequence assigns one when empty |
| Customer Reference | CustomerRef | string | No | Customer reference on the header (for example the customer's purchase order number) |
| Lines | Lines | MGCLatticeSalesOrderCaptureLineContract[] | Yes | At least one order line required |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Line Contract: MGCLatticeSalesOrderCaptureLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Item ID | ItemId | string | Yes | Item number |
| Item ID key | ItemIdExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemId. |
| Quantity | Qty | decimal | Yes | Ordered quantity; not 0 |
| Unit | UnitId | string | No | Sales unit; the item's default when empty |
| Unit Price | UnitPrice | decimal | No | Unit sales price; the trade agreement or default price when 0 |
| Site | SiteId | string | No | Ship-from site |
| Warehouse | WarehouseId | string | No | Ship-from warehouse |
| Inventory Dimension ID | InventDimId | string | No | A 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase Order ID | PurchaseOrderId | string | Yes | Purchase order number |
| Purchase Order ID key | PurchaseOrderIdExternalKey | string | No | The purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Confirmation date. Defaults to system date. |
| Lines | Lines | MGCLatticePurchPostingLineContract[] | No | Not accepted: a request with lines is refused (the whole order is confirmed) |
| Preview Mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase Order ID | PurchaseOrderId | string | Yes | Purchase order number |
| Purchase Order ID key | PurchaseOrderIdExternalKey | string | No | The purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId. |
| External System | ExternalSystem | string | No | The 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 ID | PackingSlipId | string | Yes | Product receipt/packing slip number |
| Posting Date | PostingDate | date | No | Receipt date. Defaults to system date. |
| Lines | Lines | MGCLatticePurchPostingLineContract[] | No | The lines and quantities to post; omit to post the whole order (see Posting with lines) |
| Preview Mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase Order ID | PurchaseOrderId | string | Yes | Purchase order number |
| Purchase Order ID key | PurchaseOrderIdExternalKey | string | No | The purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId. |
| External System | ExternalSystem | string | No | The 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 ID | InvoiceId | string | Yes | Vendor invoice number |
| Posting Date | PostingDate | date | No | Invoice date. Defaults to system date. |
| Lines | Lines | MGCLatticePurchPostingLineContract[] | No | The lines and quantities to post; omit to post the whole order (see Posting with lines) |
| Preview Mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase Order ID | PurchaseOrderId | string | Yes | Purchase order number |
| Purchase Order ID key | PurchaseOrderIdExternalKey | string | No | The purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId. |
| External System | ExternalSystem | string | No | The 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 ID | ProductReceiptId | string | No | The product receipt to cancel. Empty: the order's only product receipt that can be canceled |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase Order ID | PurchaseOrderId | string | Yes | Purchase order number |
| Purchase Order ID key | PurchaseOrderIdExternalKey | string | No | The purchase order's alternate key in ExternalSystem, used in place of PurchaseOrderId. |
| External System | ExternalSystem | string | No | The 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 Number | VendorInvoiceNumber | string | Yes | The vendor's invoice number; it becomes the posted invoice number (the standard duplicate checks apply) |
| Prepayment Percent | PrepaymentPercent | decimal | One of PrepaymentPercent / PrepaymentAmount when the order has no prepayment | Percentage of the order total: greater than 0, at most 100 |
| Prepayment Amount | PrepaymentAmount | decimal | One of PrepaymentPercent / PrepaymentAmount when the order has no prepayment | Fixed amount in the order currency: greater than 0, at most the order total |
| Prepayment Category | PrepaymentCategoryName | string | Yes, when the order has no prepayment | Procurement category of the prepayment; it must not be the category of an order line |
| Prepayment Category Hierarchy | PrepaymentCategoryHierarchyName | string | No | Only needed when the category name exists in several procurement category hierarchies |
| Prepayment Description | PrepaymentDescription | string | No | Description of a new prepayment |
| Invoice Date | InvoiceDate | date | No | Invoice date of the prepayment invoice. Defaults as for any vendor invoice |
| Posting Date | PostingDate | date | No | Posting date. Defaults to system date. |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Transfer Order ID | TransferOrderId | string | Yes | Transfer order number |
| Transfer Order ID key | TransferOrderIdExternalKey | string | No | The transfer order's alternate key in ExternalSystem, used in place of TransferOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Ship date. Defaults to system date. |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
| Lines | Lines | MGCLatticeTransferPostingLineContract[] | No | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Transfer Order ID | TransferOrderId | string | Yes | Transfer order number |
| Transfer Order ID key | TransferOrderIdExternalKey | string | No | The transfer order's alternate key in ExternalSystem, used in place of TransferOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Receive date. Defaults to system date. |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
| Lines | Lines | MGCLatticeTransferPostingLineContract[] | No | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Inventory journal name (must match operation type) |
| Description | Description | string | No | Journal header description |
| Posting Date | PostingDate | date | No | Transaction date. Defaults to system date. |
| External System | ExternalSystem | string | No | The 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. |
| Lines | Lines | MGCLatticeInventJournalLineContract[] | Yes | At least one journal line required |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Line Contract: MGCLatticeInventJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Item ID | ItemId | string | Yes | Item number |
| Item ID key | ItemIdExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemId. |
| Inventory Dimension ID | InventDimId | string | No | Inventory dimension ID |
| Quantity | Qty | decimal | Yes | Journal line quantity; in a counting journal, the counted quantity |
| Cost Price | CostPrice | decimal | No | Unit cost price |
| Cost Amount | CostAmount | decimal | No | Total cost amount |
| Offset Main Account ID | OffsetMainAccountId | string | No | Counter-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 ID | ToInventDimId | string | No | Target 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | No | A BOM journal name. Empty: the BOM journal name of the inventory parameters |
| Description | Description | string | No | Journal description. Defaults to the journal name's |
| Posting Date | PostingDate | date | No | The date the items are reported as finished; it also selects the BOM version. Defaults to system date. |
| External System | ExternalSystem | string | No | The external system of the lines' ...ExternalKey members. See Cross-reference keys. |
| Lines | Lines | MGCLatticeInventBOMJournalLineContract[] | Yes | One line per BOM item |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Line Contract: MGCLatticeInventBOMJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Item ID | ItemId | string | Yes | The BOM item: stocked, and one that can be produced |
| Item ID key | ItemIdExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemId. |
| Quantity | Qty | decimal | Yes | Quantity reported as finished, in the inventory unit; greater than zero |
| Inventory Dimension ID | InventDimId | string | No | Receipt dimensions |
| Site | SiteId | string | No | Receipt site, on top of InventDimId |
| Warehouse | WarehouseId | string | No | Receipt 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 ID | BOMId | string | No | The 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 key | BOMIdExternalKey | string | No | The 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | No | A tag counting journal name. Empty: the tag counting journal name of the inventory parameters |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | The counting date; the counted quantities are compared with on-hand at this date. Defaults to system date. |
| Post Counting Journal | PostCountingJournal | boolean | No | true also posts the counting journal. Default false: the counting journal is left open for review, as in the standard |
| External System | ExternalSystem | string | No | The external system of the lines' ...ExternalKey members. See Cross-reference keys. |
| Lines | Lines | MGCLatticeInventTagJournalLineContract[] | Yes | One line per tag |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Line Contract: MGCLatticeInventTagJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Tag Number | TagNumber | string | Yes | Tag number, unique in the request (compared without regard to case), at most 10 characters. A longer number is refused, never shortened |
| Tag Status | TagStatus | integer | No | Sent as a number: 1 Used, 2 Voided, 3 Missing. Empty or 0: Used |
| Item ID | ItemId | string | Used tags | The counted item. Not allowed on a voided or missing tag |
| Item ID key | ItemIdExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemId. |
| Quantity | Qty | decimal | Used tags | Counted quantity, in the inventory unit; 0 or more. Not allowed on a voided or missing tag |
| Inventory Dimension ID | InventDimId | string | No | Where the tag was counted |
| Site | SiteId | string | No | Site where the tag was counted, on top of InventDimId |
| Warehouse | WarehouseId | string | No | Warehouse 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | No | An ownership change journal name. Empty: the ownership change journal name of the inventory parameters (USMF has none set: send IOwner) |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | Date of the ownership change; the purchase order is received on it. Defaults to system date. |
| External System | ExternalSystem | string | No | The external system of the lines' ...ExternalKey members. See Cross-reference keys. |
| Lines | Lines | MGCLatticeInventOwnershipJournalLineContract[] | Yes | At least one line required |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Line Contract: MGCLatticeInventOwnershipJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Item ID | ItemId | string | Yes | The item; it must track the Owner dimension |
| Item ID key | ItemIdExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemId. |
| Quantity | Qty | decimal | Yes | Quantity, in the inventory unit; greater than zero |
| Vendor Account | VendAccount | string | Yes, unless InventDimId carries the owner | The vendor that owns the stock now (its inventory owner) |
| Vendor Account key | VendAccountExternalKey | string | No | The vendor's alternate key in ExternalSystem, used in place of VendAccount. |
| Inventory Dimension ID | InventDimId | string | No | Dimensions of the vendor-owned stock |
| Site | SiteId | string | No | Site of the vendor-owned stock, on top of InventDimId |
| Warehouse | WarehouseId | string | No | Warehouse 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:
| ErrorCode | When |
|---|---|
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; withItemIds, only the pending prices of those items. - When none of
ActivateCostPrice,ActivatePurchasePriceandActivateSalesPriceis set, cost prices only are activated (the new standard costs). ActivateCostCategoryPricesalso 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 withItemIds.- A request with nothing eligible to activate (no pending price of the requested price types and items dated today or earlier, and
ActivateCostCategoryPricesnot set) is refused withBusinessRule. - The operation has no preview:
PreviewMode: trueis refused withPreviewUnsupportedbefore any other check. Like every Lattice operation it is idempotent onRequestId(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 withsubmitAsyncOperation(see 21. Async Operations).
Request Contract: MGCLatticePendingPriceActivationRequestContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Costing Version ID | CostingVersionId | string | Yes | The 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 Price | ActivateCostPrice | boolean | No | Activate pending cost prices. When none of the three price-type members is set, cost prices are activated. |
| Activate Purchase Price | ActivatePurchasePrice | boolean | No | Activate pending purchase prices |
| Activate Sales Price | ActivateSalesPrice | boolean | No | Activate pending sales prices |
| Activate Cost Category Prices | ActivateCostCategoryPrices | boolean | No | Also 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 Exists | SkipIfEqualPriceExists | boolean | No | Leave a pending price that equals the active price pending |
| Item IDs | ItemIds | string[] | No | Activate 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 Mode | PreviewMode | boolean | No | Not 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:
| Outcome | PostedDocumentId | Message |
|---|---|---|
| Prices activated, on-hand inventory revalued | The revaluation voucher | Activated 1 pending price(s) in costing version 10: M0001. On-hand inventory was revalued on voucher IAV-000041. |
| Prices activated, nothing revalued | Empty | Activated 2 pending price(s) in costing version 10: M0001, M0004. |
| No item price activated | Empty | No 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:
| ErrorCode | When |
|---|---|
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
ItemIdsthe run succeeds when it recorded at least one pending price. WithItemIdsevery named item must get a pending cost price; otherwise the request fails withBusinessRulenaming those items, while the prices calculated for the other items stay recorded (calling again recalculates them). - The operation has no preview:
PreviewMode: trueis refused withPreviewUnsupportedbefore any other check. It is idempotent onRequestId. A whole costing version can outlast a synchronous call, so the operation can also be queued withsubmitAsyncOperation(see 21. Async Operations).
Request Contract: MGCLatticeItemCostCalculationRequestContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Costing Version ID | CostingVersionId | string | Yes | The 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 ID | SiteId | string | When the version has no site | The site the costs are calculated for. A version restricted to a site calculates for that site: send it or leave it empty |
| Calculation Date | CalculationDate | date | No | The 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 IDs | ItemIds | string[] | No | Items 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 Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Production ID | ProdId | string | Yes | Production order number |
| Production ID key | ProdIdExternalKey | string | No | The production order's alternate key in ExternalSystem, used in place of ProdId. |
| External System | ExternalSystem | string | No | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Production ID | ProdId | string | Yes | Production order number |
| Production ID key | ProdIdExternalKey | string | No | The production order's alternate key in ExternalSystem, used in place of ProdId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Start date. Defaults to system date. |
| Start Quantity | StartQty | decimal | No | Quantity 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Production ID | ProdId | string | Yes | Production order number |
| Production ID key | ProdIdExternalKey | string | No | The production order's alternate key in ExternalSystem, used in place of ProdId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Pick list date. Defaults to system date. |
| Lines | Lines | MGCLatticeProductionPickListLineContract[] | Yes | At 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Item ID | ItemId | string | Yes, unless InventTransId is sent | BOM component item number |
| Item ID key | ItemIdExternalKey | string | No | The component's released product's alternate key in ExternalSystem, used in place of ItemId. |
| Quantity | Qty | decimal | Yes | Consumption quantity, greater than zero, in the BOM line's unit (the item's BOM unit for a new BOM line) |
| Inventory Dim ID | InventDimId | string | No | Inventory dimension to consume from |
| Lot ID | InventTransId | string | No | Lot 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Production ID | ProdId | string | Yes | Production order number |
| Production ID key | ProdIdExternalKey | string | No | The production order's alternate key in ExternalSystem, used in place of ProdId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Route card date. Defaults to system date. |
| Lines | Lines | MGCLatticeProductionRouteCardLineContract[] | Yes | At 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Operation Number | OprNum | integer | Yes | Route operation number |
| Hours | Hours | decimal | No | Process hours. A line needs hours, a good quantity or an error quantity. |
| Good Quantity | GoodQty | decimal | No | Quantity completed successfully |
| Error Quantity | ErrorQty | decimal | No | Quantity 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Production ID | ProdId | string | Yes | Production order number |
| Production ID key | ProdIdExternalKey | string | No | The production order's alternate key in ExternalSystem, used in place of ProdId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Report date. Defaults to system date. |
| Good Quantity | GoodQty | decimal | No | Quantity completed successfully. A report that does not end the job needs a good or an error quantity. |
| Error Quantity | ErrorQty | decimal | No | Quantity with defects |
| End Job | EndJob | boolean | No | The 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 Error | AcceptError | boolean | No | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Production ID | ProdId | string | Yes | Production order number |
| Production ID key | ProdIdExternalKey | string | No | The production order's alternate key in ExternalSystem, used in place of ProdId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Calculation 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.
| Service | Service Group | Operations |
|---|---|---|
MGCLatticeSalesReturnService | MGCLatticeAccountsReceivableServiceGroup | createSalesReturn, receiveSalesReturn, creditSalesReturn (+ Batch) |
MGCLatticePurchaseReturnService | MGCLatticeAccountsPayableServiceGroup | createPurchaseReturn, shipPurchaseReturn, creditPurchaseReturn (+ Batch) |
Common rules of the six operations:
DocumentIdis the return order number;PostedDocumentIdis 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 sameRequestIdreturns both.- A request without the order number (
SalesOrderId/PurchaseOrderId, after any external key is resolved) fails withValidationFailed, naming the member. - The operations have no preview: a request with
PreviewMode: trueis refused withErrorCodePreviewUnsupportedbefore 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Sales order ID | SalesOrderId | string | Yes | Sales return order number |
| Sales order ID key | SalesOrderIdExternalKey | string | No | The return order's alternate key in ExternalSystem, used in place of SalesOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Receipt date. Defaults to system date. |
| Disposition Code | DispositionCode | string | Lines without one | Applied 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 mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Sales order ID | SalesOrderId | string | Yes | Sales return order number |
| Sales order ID key | SalesOrderIdExternalKey | string | No | The return order's alternate key in ExternalSystem, used in place of SalesOrderId. |
| External System | ExternalSystem | string | No | The 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 Date | PostingDate | date | No | Credit date. Defaults to system date. |
| Preview mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Customer | CustAccount | string | Sales: Yes | Customer the goods come back from |
| Customer key | CustAccountExternalKey | string | No | Sales only. The customer's alternate key in ExternalSystem, used in place of CustAccount. |
| Return reason | ReturnReasonCodeId | string | Sales: Yes; purchase: No | Header return reason code; it applies to every line |
| Return deadline | ReturnDeadline | date | No | Sales only |
| Vendor | VendAccount | string | Purchase: Yes | Vendor the goods go back to |
| Vendor key | VendAccountExternalKey | string | No | Purchase only. The vendor's alternate key in ExternalSystem, used in place of VendAccount. |
| RMA number | ReturnItemNum | string | Purchase: Yes | The vendor's return authorization (max. 10 characters); F&O does not save a return order without one |
| External System | ExternalSystem | string | No | The 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. |
| Lines | Lines | MGCLatticeReturnLineContract[] | Yes | ItemId, 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 mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase order ID | PurchaseOrderId | string | Yes | Purchase return order number |
| Purchase order ID key | PurchaseOrderIdExternalKey | string | No | The purchase return order's alternate key in ExternalSystem, used in place of PurchaseOrderId. |
| External System | ExternalSystem | string | No | The 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 number | PackingSlipId | string | Yes | The return shipment (product receipt) number |
| Posting Date | PostingDate | date | No | Ship date. Defaults to system date. |
| Preview mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase order ID | PurchaseOrderId | string | Yes | Purchase return order number |
| Purchase order ID key | PurchaseOrderIdExternalKey | string | No | The purchase return order's alternate key in ExternalSystem, used in place of PurchaseOrderId. |
| External System | ExternalSystem | string | No | The 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 number | InvoiceId | string | Yes | The vendor's credit note number |
| Posting Date | PostingDate | date | No | Credit date. Defaults to system date. |
| Preview mode | PreviewMode | boolean | No | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Invoice Account | InvoiceAccount | string | Yes | Customer account number |
| Invoice Account key | InvoiceAccountExternalKey | string | No | The customer's alternate key in ExternalSystem, used in place of InvoiceAccount. |
| External System | ExternalSystem | string | No | The 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 Code | CurrencyCode | string | No | Invoice currency (defaults from customer) |
| Posting Date | PostingDate | date | No | Invoice date. Defaults to system date. |
| Due Date | DueDate | date | No | Payment due date |
| Lines | Lines | MGCLatticeFreeTextInvoiceLineContract[] | Yes | At least one invoice line required |
Line Contract: MGCLatticeFreeTextInvoiceLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Description | Description | string | No | Line description |
| Main Account ID | MainAccountId | string | No | Revenue main account number |
| Amount | AmountCur | decimal | One of AmountCur / UnitPrice | Line amount in the invoice currency. When 0 it is Quantity x UnitPrice; when both are sent it must equal Quantity x UnitPrice |
| Quantity | Quantity | decimal | No | Quantity (defaults to 1) |
| Unit Price | UnitPrice | decimal | One of AmountCur / UnitPrice | Price per unit. When 0 it is AmountCur / Quantity |
| Sales Tax Group | SalesTaxGroup | string | No | Sales tax group code |
| Item Sales Tax Group | ItemSalesTaxGroup | string | No | Item 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Invoice RecId | InvoiceRecId | integer | One of InvoiceRecId / InvoiceId | D365 RecId of the posted CustInvoiceTable record; wins when both are sent |
| Invoice ID | InvoiceId | string | One of InvoiceRecId / InvoiceId | The posted free text invoice number, resolved to the record when InvoiceRecId is not sent |
| Invoice RecId key | InvoiceRecIdExternalKey | string | No | The free text invoice's alternate key in ExternalSystem, used in place of InvoiceRecId. |
| External System | ExternalSystem | string | No | The 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 Date | CancelDate | date | No | Date for the correcting invoice. Defaults to system date. |
| Reason Code | ReasonCode | string | Yes | Financial reason code (ReasonTable, customer-enabled - USMF: ERROR, OTHER, ...). F&O will not save a correction without one. |
| Reason Comment | ReasonComment | string | No | Cancellation 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Ledger journal name (must be Daily type) |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | Default transaction date. Defaults to system date. |
| External System | ExternalSystem | string | When a line sends an external key | The external system of the lines' AccountNumExternalKey / OffsetAccountNumExternalKey (an id from System administration > Setup > Lattice > External systems). See Cross-reference keys. |
| Lines | Lines | MGCLatticeGeneralJournalLineContract[] | Yes | At least one journal line required |
Line Contract: MGCLatticeGeneralJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Main Account ID | MainAccountId | string | Yes, unless the line uses AccountType / AccountNum | Main account number for the debit/credit entry |
| Offset Main Account ID | OffsetMainAccountId | string | No | Offset account number |
| Account Type | AccountType | integer | No | Type of AccountNum: 0 Ledger (default), 1 Customer, 2 Vendor, 6 Bank. Not with MainAccountId |
| Account | AccountNum | string | With AccountType | Main account, customer account, vendor account or bank account id |
| Account External Key | AccountNumExternalKey | string | No | The customer's or vendor's alternate key in ExternalSystem, in place of AccountNum. Not for main accounts or bank accounts |
| Offset Account Type | OffsetAccountType | integer | No | Type of OffsetAccountNum, same values. Not with OffsetMainAccountId |
| Offset Account | OffsetAccountNum | string | With an offset type other than 0 | The offset account; none = the line balances against the other lines of its voucher |
| Offset Account External Key | OffsetAccountNumExternalKey | string | No | The offset customer's or vendor's alternate key in ExternalSystem (resolved in the offset company of an intercompany line) |
| Debit Amount | AmountCurDebit | decimal | No | Debit amount in transaction currency |
| Credit Amount | AmountCurCredit | decimal | No | Credit amount in transaction currency |
| Currency Code | CurrencyCode | string | On a line whose account is a main account | Transaction currency. A customer, vendor or bank line takes the account's currency |
| Description | Description | string | No | Line description/voucher text |
| Transaction Date | TransDate | date | No | Line-level transaction date (overrides header) |
| Offset Company | OffsetCompany | string | No | postIntercompanyJournal only: the legal entity the offset posts in. Refused by postGeneralJournal |
| Invoice | InvoiceId | string | No | The 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 Number | DocumentNumber | string | No | Document number |
| Document Date | DocumentDate | date | No | Document date (a vendor invoice line's due date is calculated from it) |
| Due Date | DueDate | date | No | Customer or vendor line only. Default: calculated from the terms of payment |
| Terms of Payment | PaymentTermsId | string | No | Customer or vendor line only. Default: the account's terms of payment |
| Posting Profile | PostingProfile | string | No | Customer or vendor line only. Default: the accounts receivable / payable parameters' posting profile |
| Sales Tax Group | SalesTaxGroup | string | No | Default: the customer's or vendor's sales tax group, or the main account's |
| Item Sales Tax Group | ItemSalesTaxGroup | string | No | Default: the ledger account's or the default item sales tax group (on a customer or vendor line only with an invoice number) |
| Method of Payment | MethodOfPayment | string | No | Customer or vendor line only. Default: the account's method of payment |
| Payment Reference | PaymentReference | string | No | Payment reference |
| Bank Transaction Type | BankTransactionType | string | No | Line with a bank account only |
| Dimensions | Dimensions | MGCLatticeDimensionValueContract[] | No | Financial 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:
| ErrorCode | When |
|---|---|
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:
| Voucher | Standard reversal |
|---|---|
| General ledger transactions only, posted with transaction type General journal, Allocation or Elimination | Transaction reversal (TransactionReversal_Ledger) |
| A customer transaction not posted to a bank account | Customer transaction reversal (TransactionReversal_Cust) |
| A vendor transaction not posted to a bank account | Vendor transaction reversal (TransactionReversal_Vend) |
| A customer payment posted to a bank account | Payment cancellation (BankPaymCancel), which also reverses its settlements |
| Any other bank voucher, fixed asset or project transactions | Not 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Number | JournalNum | string | One of JournalNum / JournalNumExternalKey / Voucher | The posted journal |
| Journal Number key | JournalNumExternalKey | string | No | The journal's alternate key in ExternalSystem, used in place of JournalNum. |
| External System | ExternalSystem | string | No | The 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. |
| Voucher | Voucher | string | No | One voucher of the journal to reverse. Sent alone, it names the journal that contains it |
| Reversal Date | ReversalDate | date | No | Date of the reversal. Defaults to system date; not before a voucher's date |
| Reason Code | ReasonCode | string | When the parameters demand one | Financial 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 Comment | ReasonComment | string | No | Reason text |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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.
| Operation | Journals | Standard posting |
|---|---|---|
postLedgerJournal | General journal, customer payment journal, vendor payment journal, invoice register, vendor invoice journal, invoice approval journal, project expense journal, fixed asset journal | The journal page's Post (not Post and transfer): one voucher that fails cancels the whole posting |
postInventoryJournal | Movement, profit/loss (adjustment), counting, transfer, BOM, tag counting, ownership change, project item and fixed asset inventory journals | The inventory journal posting of the journal type |
postProjectJournal | Project hour and fee journals | The project journal posting |
postProductionJournal | Picking list, route card, job card and report as finished journals | The production journal posting of the journal type |
postTradeAgreementJournal | Trade 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)
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Number | JournalNum | string | One of JournalNum / JournalNumExternalKey | The ledger journal (journal batch number) |
| Journal Number key | JournalNumExternalKey | string | No | The journal's alternate key in ExternalSystem, used in place of JournalNum. |
| External System | ExternalSystem | string | No | The external system whose keys the request sends (an id from System administration > Setup > Lattice > External systems). Needed with JournalNumExternalKey. See Cross-reference keys. |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Request Contract: MGCLatticeJournalPostingRequestContract (postInventoryJournal, postProjectJournal, postProductionJournal)
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal ID | JournalId | string | Yes | The journal number of the inventory, project or production journal |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Request Contract: MGCLatticeTradeAgreementJournalPostingRequestContract (postTradeAgreementJournal)
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Number | JournalNum | string | Yes | The trade agreement journal number |
| Preview Mode | PreviewMode | boolean | No | Not 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 type | Operation the caller must hold |
|---|---|
| General journal | MGCLatticeGeneralLedgerJournalService.postGeneralJournal |
| Customer payment journal | MGCLatticePaymentJournalService.postCustomerPaymentJournal |
| Vendor payment journal | MGCLatticePaymentJournalService.postVendorPaymentJournal |
| Invoice register, vendor invoice journal | MGCLatticeVendorInvoiceJournalService.postInvoiceRegisterJournal |
| Invoice approval journal | MGCLatticeVendorInvoiceJournalService.postInvoiceApprovalJournal |
| Project expense journal (ledger, type Cost) | MGCLatticeProjectJournalService.postExpenseJournal |
| Fixed asset journal | Decided 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 journal | MGCLatticeInventoryJournalPostingService.postMovementJournal / postAdjustmentJournal / postCountingJournal / postTransferJournal / postBOMJournal / postTagCountingJournal / postOwnershipChangeJournal |
| Project item journal (inventory, type Project) | MGCLatticeProjectJournalService.postItemJournal |
| Project hour / fee journal | MGCLatticeProjectJournalService.postHourJournal / postFeeJournal |
| Picking list / route card and job card / report as finished journal | MGCLatticeProductionOrderPostingService.postPickList / postRouteCard / reportAsFinished |
| Trade agreement journal | MGCLatticeSalesTradeAgreementService.setSalesPrice |
In addition, by line, in a ledger journal of any type:
| Line | Operation 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 Acquisition | MGCLatticeFixedAssetService.postAcquisition |
| Fixed asset line with transaction type Disposal - sale or Disposal - scrap | MGCLatticeFixedAssetService.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:
| ErrorCode | When |
|---|---|
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 inWarnings. - 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:
| ErrorCode | When |
|---|---|
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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Payment journal name |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | Default transaction date |
| External System | ExternalSystem | string | No | The 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 Payments | GeneratePayments | boolean | No | postVendorPaymentJournal only: true generates the checks of the lines that need them before the journal posts (see Check payments above). Default false. Refused by postCustomerPaymentJournal |
| Lines | Lines | MGCLatticePaymentJournalLineContract[] | Yes | At least one payment line required |
Line Contract: MGCLatticePaymentJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Account Number | AccountNum | string | Yes | Customer or vendor account number |
| Account Number key | AccountNumExternalKey | string | No | The customer's (customer payment journal) or vendor's (vendor payment journal) alternate key in ExternalSystem, used in place of AccountNum. |
| Debit Amount | AmountCurDebit | decimal | No | Debit amount |
| Credit Amount | AmountCurCredit | decimal | No | Credit amount |
| Currency Code | CurrencyCode | string | No | Transaction currency. Defaults to the customer's or vendor's currency |
| Bank Account ID | BankAccountId | string | No | The 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 Payment | MethodOfPayment | string | No | Payment method code |
| Invoice ID | InvoiceId | string | No | Customer 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 |
| Description | Description | string | No | Payment description |
| Transaction Date | TransDate | date | No | Line-level date |
| Prepayment | IsPrepayment | boolean | No | true makes the line a prepayment (see Prepayments above). Default false |
| Sales Order ID | SalesOrderId | string | No | Customer payments only: the sales order the payment is marked against. Refused on vendor payment lines |
| Sales Order ID key | SalesOrderIdExternalKey | string | No | The sales order's alternate key in ExternalSystem, used in place of SalesOrderId. |
| Purchase Order ID | PurchaseOrderId | string | No | Vendor payments only: the purchase order the payment is marked against. Refused on customer payment lines |
| Purchase Order ID key | PurchaseOrderIdExternalKey | string | No | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Account Number | AccountNum | string | Yes | Customer or vendor account number |
| Account Number key | AccountNumExternalKey | string | No | The customer's (customer settlement) or vendor's (vendor settlement) alternate key in ExternalSystem, used in place of AccountNum. |
| External System | ExternalSystem | string | No | The 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 RecId | PaymentTransRecId | integer | One of the three | RecId of the payment transaction (CustTrans/VendTrans) of AccountNum |
| Payment Voucher | PaymentVoucher | string | One of the three | Used when PaymentTransRecId is not sent: the voucher of the posted payment. The way to identify a vendor payment |
| Payment Invoice ID | PaymentInvoiceId | string | One of the three | Used when neither PaymentTransRecId nor PaymentVoucher is sent: the invoice number the payment carries (a customer payment posted with a line InvoiceId) |
| Lines | Lines | MGCLatticeSettlementLineContract[] | Yes | At least one settlement line required |
Line Contract: MGCLatticeSettlementLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Invoice Trans RecId | InvoiceTransRecId | integer | One of the two | RecId of the transaction of AccountNum to settle against (not a payment) |
| Invoice ID | InvoiceId | string | One of the two | Used when InvoiceTransRecId is not sent: the invoice number of a transaction of AccountNum |
| Settle Amount | SettleAmountCur | decimal | No | Amount 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:
| Payment | Customer | Vendor |
|---|---|---|
| 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 check | Payment cancellation (BankPaymCancel): it reverses the payment's settlements, so the invoices it paid are open again | Refused with BusinessRule: the standard reverses a vendor payment to a bank account only as a check reversal |
| Not posted to a bank account | Transaction 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Account Number | AccountNum | string | Yes | The customer (reverseCustomerPayment) or vendor (reverseVendorPayment) account |
| Account Number key | AccountNumExternalKey | string | No | The customer's or vendor's alternate key in ExternalSystem, used in place of AccountNum. |
| External System | ExternalSystem | string | No | The 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. |
| Voucher | Voucher | string | Yes | The payment voucher (a transaction of type Payment of the account) |
| Reversal Date | ReversalDate | date | No | Date of the reversal. Defaults to system date; not before the payment date |
| Reason Code | ReasonCode | string | When the parameters demand one | Financial 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 Comment | ReasonComment | string | No | Reason text |
| Reversal Journal Name ID | ReversalJournalNameId | string | No | Check 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 Journal | PostReversalJournal | boolean | No | Check reversals under review only: true posts the check reversal journal in the same request. Default false (the journal is left for review) |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Workflow Type Name | WorkflowTypeName | string | Yes | D365 workflow type name (e.g., PurchReqReview) |
| Record RecId | RecordRecId | integer | One of RecordRecId / DocumentNumber | RecId of the record to submit; wins when both are sent |
| Document Number | DocumentNumber | string | One of RecordRecId / DocumentNumber | The document's number (a purchase requisition number for PurchReqTable), resolved to the record when RecordRecId is not sent |
| Table Name | TableName | string | Yes | Table name of the record: PurchReqTable |
| Comment | Comment | string | No | Submission 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Acting User | ActingUserId | string | Yes | The user the action is taken as: the work item's assignee |
| Work Item RecId | WorkItemRecId | integer | One of WorkItemRecId / WorkflowCorrelationId | RecId of the WorkflowWorkItemTable record (must be Pending and assigned to ActingUserId); wins when both are sent |
| Workflow Correlation ID | WorkflowCorrelationId | string (GUID) | One of WorkItemRecId / WorkflowCorrelationId | The workflow correlation ID submitToWorkflow returned; the pending work item of that workflow assigned to ActingUserId is acted on |
| Comment | Comment | string | No | Action comment |
| Delegate To User | DelegateToUserId | string | delegate only | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Workflow Correlation ID | WorkflowCorrelationId | string (GUID) | Yes | The workflow correlation ID returned from submitToWorkflow |
| Comment | Comment | string | No | Recall 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Budget Transaction Code | BudgetTransactionCode | string | Yes | Budget transaction code name |
| Budget Model ID | BudgetModelId | string | Yes | Budget model identifier |
| Posting Date | PostingDate | date | No | Date of the budget register entry. Defaults to today's date in the calling user's time zone. |
| Lines | Lines | MGCLatticeBudgetEntryLineContract[] | Yes | At least one budget line required |
Line Contract: MGCLatticeBudgetEntryLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Main Account ID | MainAccountId | string | Yes | Main account for the budget entry |
| Amount | Amount | decimal | Yes | Budget amount in transaction currency; not zero |
| Currency Code | CurrencyCode | string | No | Transaction currency. Defaults to the accounting currency |
| Transaction Date | TransDate | date | No | Line date. Defaults to PostingDate |
| Comment | Comment | string | No | Line 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Project ID | ProjId | string | No | Default project ID for all lines |
| Project ID key | ProjIdExternalKey | string | No | The default project's alternate key in ExternalSystem, used in place of ProjId. |
| External System | ExternalSystem | string | No | The 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 ID | JournalNameId | string | Yes | Journal name of the operation's journal kind (see above) |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | Default transaction date |
| Lines | Lines | MGCLatticeProjectJournalLineContract[] | Yes | At least one line required |
Line Contract: MGCLatticeProjectJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Project ID | ProjId | string | No | Line-level project ID (overrides header) |
| Project ID key | ProjIdExternalKey | string | No | The line's project's alternate key in ExternalSystem, used in place of ProjId. |
| Category ID | CategoryId | string | Yes | Project category |
| Quantity | Qty | decimal | Yes | Hours, quantity, or units |
| Cost Price | CostPrice | decimal | No | Cost price per unit |
| Sales Price | SalesPrice | decimal | No | Sales/billing price per unit |
| Currency Code | CurrencyCode | string | No | Transaction currency |
| Description | Description | string | No | Line description |
| Transaction Date | TransDate | date | No | Line date (overrides header) |
| Worker Personnel Number | WorkerPersonnelNumber | string | No | Personnel number of the worker the line is for (its resource); an unknown number fails with ValidationFailed |
| Item ID | ItemId | string | Item journals | Item number consumed onto the project |
| Item ID key | ItemIdExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemId. |
| Inventory Dimension ID | InventDimId | string | No | Item journals: the dimension (site / warehouse ...) the item is consumed from; empty = the item's default order settings |
| Line Property ID | LinePropertyId | string | No | Billable / NonBill ...; empty = the project line property setup default |
| Offset Main Account ID | OffsetMainAccountId | string | Expense journals | Main account the expense is paid from (credit side; the project side comes from the project posting setup) |
| Activity Number | ActivityNumber | string | No | Project 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Project ID | ProjId | string | Yes | Project to invoice |
| Project ID key | ProjIdExternalKey | string | No | The project's alternate key in ExternalSystem, used in place of ProjId. |
| External System | ExternalSystem | string | No | The 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 Date | InvoiceDate | date | No | Invoice date. Defaults to today's date in the calling user's time zone. |
| Post After Create | PostAfterCreate | boolean | No | If 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Worker Personnel Number | WorkerPersonnelNumber | string | No | Personnel number of the worker the report belongs to; empty = the calling user's worker. The worker must be employed in the legal entity |
| Purpose | Purpose | string | No | Purpose of the report |
| Description | Description | string | No | Description of the report |
| Location | Location | string | No | Location (destination) |
| Dimensions | Dimensions | MGCLatticeDimensionValueContract[] | No | Financial dimensions of the report, merged over the worker's default dimensions |
| Lines | Lines | MGCLatticeExpenseReportLineContract[] | Yes | At least one line |
| Submit To Workflow | SubmitToWorkflow | boolean | No | true submits the report to its expense report workflow after it is created. Default false |
| Comment | Comment | string | No | Workflow comment of the submit |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Line Contract: MGCLatticeExpenseReportLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Category ID | CategoryId | string | Yes | Expense category. On a line with a project it is also the project category, so it must be a category used in projects |
| Transaction Date | TransDate | date | No | Date of the expense. Defaults to today |
| Amount | Amount | decimal | Yes | Amount in CurrencyCode; not zero |
| Currency Code | CurrencyCode | string | No | Defaults to the legal entity's accounting currency |
| Payment Method | PaymentMethod | string | No | Defaults to the category's default payment method. Must be allowed for the category |
| Merchant | Merchant | string | No | Merchant |
| Description | Description | string | No | Defaults to the category's description |
| Business Purpose | BusinessPurpose | string | No | Business purpose |
| Additional Information | AdditionalInformation | string | No | Additional information |
| Sales Tax Group | SalesTaxGroup | string | No | Defaults to the group the expense line defaults (worker, project, tax setup) |
| Item Sales Tax Group | ItemSalesTaxGroup | string | No | Defaults to the category's item sales tax group |
| Project ID | ProjId | string | No | Project the expense is charged to |
| Activity Number | ActivityNumber | string | No | Project activity; only with ProjId |
| Dimensions | Dimensions | MGCLatticeDimensionValueContract[] | No | Financial 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Expense Report Number | ExpenseReportNumber | string | Yes | The expense report to post |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Fixed asset journal name |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | Acquisition date. Defaults to system date. |
| External System | ExternalSystem | string | No | The 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. |
| Lines | Lines | MGCLatticeFixedAssetAcquisitionLineContract[] | Yes | At least one acquisition line required |
Line Contract: MGCLatticeFixedAssetAcquisitionLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Asset ID | AssetId | string | Yes | Fixed asset number |
| Asset ID key | AssetIdExternalKey | string | No | The fixed asset's alternate key in ExternalSystem, used in place of AssetId. |
| Asset Book ID | AssetBookId | string | Yes | Depreciation book ID |
| Acquisition Amount | AcquisitionAmount | decimal | Yes | Purchase/acquisition cost; not zero |
| Currency Code | CurrencyCode | string | No | Transaction currency. Defaults to the accounting currency |
| Offset Main Account | OffsetMainAccountId | string | No | Offset GL account |
| Description | Description | string | No | Line 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Fixed asset journal name |
| Asset Book ID | AssetBookId | string | No | Depreciation book to process; empty for every book |
| Depreciation Date | DepreciationDate | date | No | Run 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Fixed asset journal name |
| Asset ID | AssetId | string | Yes | Fixed asset to dispose |
| Asset ID key | AssetIdExternalKey | string | No | The fixed asset's alternate key in ExternalSystem, used in place of AssetId. |
| External System | ExternalSystem | string | No | The 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 ID | AssetBookId | string | Yes | Depreciation book |
| Is Sale | IsSale | boolean | No | true for disposal-sale, false (the default when omitted) for disposal-scrap |
| Sale Amount | SaleAmount | decimal | No | Sale proceeds (only applicable when IsSale is true) |
| Offset Main Account | OffsetMainAccountId | string | No | Offset main account for the sale proceeds; one that does not resolve fails the request with DimensionValueNotFound |
| Currency Code | CurrencyCode | string | No | Transaction currency. Defaults to the accounting currency |
| Disposal Date | DisposalDate | date | No | Disposal 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | A fixed asset journal name; its posting layer must be the posting layer of every line's book |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | Default transaction date of the lines. Defaults to today |
| External System | ExternalSystem | string | No | The external system of the lines' AssetIdExternalKey. See Cross-reference keys. |
| Lines | Lines | MGCLatticeFixedAssetTransactionLineContract[] | Yes | At least one line |
| Preview Mode | PreviewMode | boolean | No | Not supported: true is refused with PreviewUnsupported |
Line Contract: MGCLatticeFixedAssetTransactionLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Asset ID | AssetId | string | Yes | Fixed asset |
| Asset ID key | AssetIdExternalKey | string | No | The asset's alternate key in ExternalSystem, used in place of AssetId. |
| Asset Book ID | AssetBookId | string | Yes | Book of the asset; it must be acquired |
| Transaction Type | TransactionType | string | Yes | AcquisitionAdj, Depreciation, DepreciationAdj, Revaluation, WriteUpAdj, WriteDownAdj, ExtraordinaryDepreciation or BonusDepreciation (not case-sensitive). Acquisitions are posted with postAcquisition, disposals with postDisposal |
| Debit Amount | DebitAmount | decimal | One of the two | Amount in the accounting currency that increases the book's value |
| Credit Amount | CreditAmount | decimal | One of the two | Amount in the accounting currency that decreases the book's value (a depreciation or write-down is a credit) |
| Transaction Date | TransactionDate | date | No | Defaults to PostingDate |
| Offset Main Account | OffsetMainAccountId | string | No | Offset main account. Defaults to the posting profile's offset account for the type and book |
| Dimensions | Dimensions | MGCLatticeDimensionValueContract[] | No | Replace these dimensions of the book's financial dimensions on the line; the other dimensions keep their values |
| Consumption Quantity | ConsumptionQuantity | decimal | No | Consumption of a depreciation line of a book that depreciates by consumption |
| Reason Code | ReasonCode | string | No | Financial reason; required when the fixed asset parameters demand a reason for the type |
| Reason Comment | ReasonComment | string | No | Reason comment |
| Description | Description | string | No | Line 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Asset ID | AssetId | string | Yes | Fixed asset |
| Asset ID key | AssetIdExternalKey | string | No | The asset's alternate key in ExternalSystem, used in place of AssetId. |
| External System | ExternalSystem | string | No | The external system of AssetIdExternalKey. See Cross-reference keys. |
| Asset Book ID | AssetBookId | string | No | The one book to transfer. Without it, every open or closed book of the asset that has a posting layer is transferred |
| Dimensions | Dimensions | MGCLatticeDimensionValueContract[] | One of Dimensions / LocationId | The financial dimension values the asset moves to |
| Location | LocationId | string | One of Dimensions / LocationId | The fixed asset location the asset moves to |
| Transfer Date | TransferDate | date | No | Defaults to today; it must be valid in the fiscal calendar |
| Comment | Comment | string | No | Transfer comment, written to the transfer history and transactions |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Asset ID | AssetId | string | Yes | Fixed asset to split |
| Asset ID key | AssetIdExternalKey | string | No | The asset's alternate key in ExternalSystem, used in place of AssetId. |
| Asset Book ID | AssetBookId | string | Yes | Book to split; it must be acquired |
| To Asset ID | ToAssetId | string | No | Existing asset that receives the split. Empty creates a new asset |
| To Asset ID key | ToAssetIdExternalKey | string | No | The receiving asset's alternate key in ExternalSystem, used in place of ToAssetId. |
| To Asset Book ID | ToAssetBookId | string | No | Book of the receiving asset. Defaults to AssetBookId |
| Percent | Percent | decimal | One of Percent / Quantity | Share to split off, greater than 0 and at most 100 |
| Quantity | Quantity | decimal | One of Percent / Quantity | Units to split off, at most the asset's quantity |
| Split Date | SplitDate | date | No | Defaults to today |
| Journal Name ID | JournalNameId | string | Yes | Fixed asset journal name of the split journal, on the books' posting layer |
| External System | ExternalSystem | string | No | The external system of the keys. See Cross-reference keys. |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Asset ID | AssetId | string | Yes | Fixed asset |
| Asset ID key | AssetIdExternalKey | string | No | The asset's alternate key in ExternalSystem, used in place of AssetId. |
| Asset Book ID | AssetBookId | string | Yes | Book of the transaction |
| Voucher | Voucher | string | Yes | Voucher of the transaction to reverse |
| Transaction Date | TransactionDate | date | No | Needed only when the voucher has transactions of the book on several dates |
| Reversal Date | ReversalDate | date | No | Defaults to today; not before the transaction's date |
| Reason Code | ReasonCode | string | No | Financial reason written on the reversal |
| Reason Comment | ReasonComment | string | No | Reason comment |
| External System | ExternalSystem | string | No | The external system of AssetIdExternalKey. See Cross-reference keys. |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Vendor payment journal name |
| From Due Date | FromDueDate | date | No | Include transactions due on or after this date; empty for no lower bound |
| To Due Date | ToDueDate | date | No | Include transactions due on or before this date. Defaults to today's date in the calling user's time zone. |
| Method of Payment | MethodOfPayment | string | No | Only 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Number | JournalNum | string | One of JournalNum / JournalNumExternalKey | An open vendor payment journal |
| Journal Number key | JournalNumExternalKey | string | No | The journal's alternate key in ExternalSystem, used in place of JournalNum. |
| External System | ExternalSystem | string | No | The 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 Payment | MethodOfPayment | string | No | Only the lines with this method; without it, the lines whose method needs generation |
| Bank Account ID | BankAccountId | string | No | Only the lines that pay from this bank account; it needs a check layout |
| Post After Generate | PostAfterGenerate | boolean | No | true posts the journal after the generation, in the same transaction. Default false |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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 type | USMF example | What posting does |
|---|---|---|
Invoice register (PurchaseLedger) | APInvReg | Posts 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") | APInvoice | Posts 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:
- finds the registered invoice (
VendAccount+InvoiceId) in the vendor invoice pool; - fetches it into a new approval journal, which brings in the lines that reverse the pending posting;
- adds the expense line on
OffsetMainAccountId(required) for the registered amount, approved by the register's approver orApproverPersonnelNumber; - posts the journal and checks that every invoice is now approved.
DocumentIdis 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Journal Name ID | JournalNameId | string | Yes | Register: an invoice register or vendor invoice journal name. Approval: an Approval journal name |
| Description | Description | string | No | Journal description |
| Posting Date | PostingDate | date | No | Default transaction date |
| External System | ExternalSystem | string | No | The 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. |
| Lines | Lines | MGCLatticeVendorInvoiceJournalLineContract[] | Yes | At least one line required |
Line Contract: MGCLatticeVendorInvoiceJournalLineContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Vendor Account | VendAccount | string | Yes | Vendor account number |
| Vendor Account key | VendAccountExternalKey | string | No | The vendor's alternate key in ExternalSystem, used in place of VendAccount. |
| Invoice ID | InvoiceId | string | No | Vendor invoice number. Required on an approval line |
| Debit Amount | AmountCurDebit | decimal | No | Debit amount |
| Credit Amount | AmountCurCredit | decimal | No | Credit amount |
| Currency Code | CurrencyCode | string | No | Transaction currency. Defaults to the vendor's currency |
| Description | Description | string | No | Line description |
| Transaction Date | TransDate | date | No | Line date |
| Invoice Date | InvoiceDate | date | No | Vendor invoice date (DocumentDate) |
| Due Date | DueDate | date | No | Payment due date. Defaults from the vendor's terms of payment |
| Offset Main Account ID | OffsetMainAccountId | string | See description | Vendor invoice journal: the offset (expense) main account. Invoice register: leave empty for the pending-invoice account. Approval: required, the expense account |
| Approver | ApproverPersonnelNumber | string | No | "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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Header Reference | HeaderReference | string | One of HeaderReference / VendorAccount + InvoiceNumber | The pending invoice's header reference (the key of VendorInvoiceHeaders) |
| Vendor Account | VendorAccount | string | With InvoiceNumber | The invoice's invoice account or vendor account |
| Vendor Account key | VendorAccountExternalKey | string | No | The vendor's alternate key in ExternalSystem, used in place of VendorAccount. |
| External System | ExternalSystem | string | No | The 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 Number | InvoiceNumber | string | With VendorAccount | The vendor's invoice number (the pending invoice's Invoice field) |
| Preview Mode | PreviewMode | boolean | No | Not 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:
| ErrorCode | When |
|---|---|
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/runVendorRevaluationrevalue the open customer / vendor transactions at the exchange rate ofRevaluationDate, forCurrencyCodeor every foreign currency. They have no period or account range:FromDate,MainAccountFromIdandMainAccountToIdare refused withValidationFailed.runLedgerRevaluationrevalues the general ledger forCurrencyCode, or else for every currency posted to the ledger in the period, fromFromDate(default: the start of the fiscal year ofRevaluationDate) throughRevaluationDate, optionally only for main accountsMainAccountFromIdthroughMainAccountToId. Both dates must fall in one fiscal year. Settings the standard revaluation rejects (for example aFromDateafterRevaluationDate) fail the request withValidationFailed. 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Revaluation Date | RevaluationDate | date | No | Revalue through this date. Defaults to today's date in the calling user's time zone. |
| From Date | FromDate | date | No | Ledger revaluation only: first date of the period. Defaults to the start of the fiscal year of RevaluationDate. |
| Currency Code | CurrencyCode | string | No | Revalue only this currency |
| Main Account From | MainAccountFromId | string | No | Start of main account range (ledger revaluation only) |
| Main Account To | MainAccountToId | string | No | End 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase Requisition ID | PurchReqId | string | Yes | Purchase requisition number |
| Purchase Requisition ID key | PurchReqIdExternalKey | string | No | The purchase requisition's alternate key in ExternalSystem, used in place of PurchReqId. |
| External System | ExternalSystem | string | No | The 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. |
| Comment | Comment | string | No | Workflow 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Purchase Requisition ID | PurchReqId | string | Yes | Purchase requisition number (must be in Approved status; InvalidStatus otherwise) |
| Purchase Requisition ID key | PurchReqIdExternalKey | string | No | The purchase requisition's alternate key in ExternalSystem, used in place of PurchReqId. |
| External System | ExternalSystem | string | No | The 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:
-
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. ReturnsSuccess: false,Status: 4(Failed), with the error message in bothMessageandErrors[]. -
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 inErrors[]. -
Runtime errors -- Runtime (CLR), deadlock and update-conflict failures return
TransientRuntime, retryable, with a generic runtime error message. -
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., classifiedUnexpectedError, not retryable (see Unexpected Error). -
Transaction safety -- All operations wrap posting logic in
ttsBegin/ttsCommitblocks. On failure, any active transaction is safely aborted before returning the error response. The service never throws unhandled exceptions to the caller. -
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;createExpenseReportlikewise deletes the expense report it created when the submit to workflow fails. The failed request releases itsRequestId, 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 withoutPostAfterCreate, 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."]
}
]
}
| Field | Type | Description |
|---|---|---|
Success | boolean | true only when every item succeeded |
Status | enum MGCLatticeServiceCallStatus | Overall outcome: Succeeded (every item succeeded), Failed (every item failed, or the request list was missing or empty) or PartialSuccess (mixed). See MGCLatticeServiceCallStatus. |
Message | string | Top-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 |
CorrelationId | GUID | Correlation ID for tracing |
TotalCount | integer | Total number of items in the batch |
SuccessCount | integer | Number of items that succeeded |
FailureCount | integer | Number of items that failed |
StartDateTimeUtc / EndDateTimeUtc | datetime | When the bulk operation started and finished |
DurationMs | integer | Elapsed time of the whole bulk operation in milliseconds |
Results | MGCLatticeBulkItemResultContract[] | Per-item results |
MGCLatticeBulkItemResultContract:
| Field | Type | Description |
|---|---|---|
ItemIndex | integer | One-based position of the item in the request list |
Success | boolean | Whether this individual item succeeded |
Status | enum MGCLatticeServiceCallStatus | Per-item lifecycle status (Succeeded or Failed). See MGCLatticeServiceCallStatus. |
ErrorCode | enum MGCLatticeServiceErrorCode | Per-item machine-readable error classification (None on success). See MGCLatticeServiceErrorCode. |
IsRetryable | boolean | Whether this individual item may be safely retried |
DocumentId | string | Document ID for this item |
PostedDocumentId | string | Number of the document this item produced (empty when none) |
RequestId | GUID | Request ID for this item |
Message | string | Result message |
Errors | string[] | 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Document Id | DocumentId | string | Yes | Sales order number to query (the contract is MGCLatticeStatusQueryRequestContract) |
| Document Id key | DocumentIdExternalKey | string | No | The sales order's alternate key in ExternalSystem, used in place of DocumentId. |
| External System | ExternalSystem | string | No | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Document Id | DocumentId | string | Yes | Purchase order number to query (the contract is MGCLatticeStatusQueryRequestContract) |
| Document Id key | DocumentIdExternalKey | string | No | The purchase order's alternate key in ExternalSystem, used in place of DocumentId. |
| External System | ExternalSystem | string | No | The external system DocumentIdExternalKey belongs to. |
getProductionOrderStatus
Service: MGCLatticeProductionOrderPostingService
Service Group: MGCLatticeProductionServiceGroup
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Document Id | DocumentId | string | Yes | Production order number to query (the contract is MGCLatticeStatusQueryRequestContract) |
| Document Id key | DocumentIdExternalKey | string | No | The production order's alternate key in ExternalSystem, used in place of DocumentId. |
| External System | ExternalSystem | string | No | The external system DocumentIdExternalKey belongs to. |
getJournalStatus
Service: MGCLatticeGeneralLedgerJournalService
Service Group: MGCLatticeGeneralLedgerServiceGroup
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Document Id | DocumentId | string | Yes | Ledger journal number to query (the contract is MGCLatticeStatusQueryRequestContract) |
| Document Id key | DocumentIdExternalKey | string | No | The journal's alternate key in ExternalSystem, used in place of DocumentId. |
| External System | ExternalSystem | string | No | The external system DocumentIdExternalKey belongs to. |
getWorkflowStatus
Service: MGCLatticeWorkflowActionService
Service Group: MGCLatticeWorkflowServiceGroup
Request Contract: MGCLatticeStatusQueryRequestContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Document Id | DocumentId | string | Yes, unless an external key is sent | Any 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 / Key | ExternalSystem, DocumentIdExternalKey | string | No | A 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):
| Field | Type | Description |
|---|---|---|
Success | boolean | Whether the query found the document |
ErrorCode | enum MGCLatticeServiceErrorCode | Why a query failed, as on the common response (for example ValidationFailed for a request without DocumentId, DocumentNotFound for an unknown document); None on success |
Message | string | Result or error text |
Errors | string[] | The error messages of a failed query |
CorrelationId | GUID | Echoed from the request |
DocumentId | string | The document that was queried |
DocumentType | string | The kind of document, for example SalesOrder |
DocumentStatus | string | Current status of the document (e.g., Backorder, Delivered, Invoiced) |
LastModifiedDateTimeUtc | datetime | When the document was last changed (UTC) |
StatusDetails | object[] | 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 operations | Privilege that grants them |
|---|---|
MGCLatticeFixedAssetService runDepreciationProposal, postAcquisition, postAssetTransaction | MGCLatticeFixedAssetsServiceMaintain |
MGCLatticeFixedAssetService postDisposal | MGCLatticeFixedAssetsDisposalMaintain |
MGCLatticeJournalPostingService (all five) | MGCLatticeJournalPostingMaintain; the journal's own operations are checked when it posts (see 8a) |
MGCLatticeInventoryCostService activatePendingPrices | MGCLatticeInventoryCostActivateMaintain |
MGCLatticeInventoryCostService calculateItemCosts | MGCLatticeInventoryCostCalculateMaintain |
MGCLatticeCurrencyRevaluationService (all three), MGCLatticeGeneralLedgerJournalService postGeneralJournal, MGCLatticeBudgetRegisterService (both) | MGCLatticeGeneralLedgerServiceMaintain |
MGCLatticeGeneralLedgerJournalService postIntercompanyJournal | MGCLatticeGeneralLedgerIntercompanyMaintain |
MGCLatticeGeneralLedgerJournalService reverseJournal | MGCLatticeGeneralLedgerJournalReverseMaintain |
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Correlation ID | CorrelationId | string (GUID) | No | Stored on the tracking record and echoed in the response |
| Request ID | RequestId | string (GUID) | Yes | The submission's idempotency key: a repeat returns the first submission's tracking ID |
| Legal Entity | LegalEntityId | string | No | Recorded on the tracking record; defaults to the payload's LegalEntityId |
| User Context | UserContext | string | No | Informational; recorded on the tracking record. The submitting user is the record's SubmittedBy |
| Service Name | ServiceName | string | Yes | The Lattice service that owns the operation (see supported operations below) |
| Operation Name | OperationName | string | Yes | The service operation to run |
| Request Payload | RequestPayload | string | Yes | The 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.
getAsyncOperationStatusreturnsStatus4(Failed) andErrorCodeOperationDisabled, withMessageandErrorsThe 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 codeOperationDisabled) 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:
| ServiceName | OperationName | Request payload contract |
|---|---|---|
MGCLatticeFixedAssetService | runDepreciationProposal | MGCLatticeFixedAssetDepreciationRequestContract |
MGCLatticeFixedAssetService | postAcquisition | MGCLatticeFixedAssetAcquisitionRequestContract |
MGCLatticeFixedAssetService | postDisposal | MGCLatticeFixedAssetDisposalRequestContract |
MGCLatticeFixedAssetService | postAssetTransaction | MGCLatticeFixedAssetTransactionRequestContract |
MGCLatticeCurrencyRevaluationService | runCustomerRevaluation, runVendorRevaluation, runLedgerRevaluation | MGCLatticeCurrencyRevaluationRequestContract |
MGCLatticeInventoryCostService | activatePendingPrices | MGCLatticePendingPriceActivationRequestContract |
MGCLatticeInventoryCostService | calculateItemCosts | MGCLatticeItemCostCalculationRequestContract |
MGCLatticeGeneralLedgerJournalService | postGeneralJournal, postIntercompanyJournal | MGCLatticeGeneralJournalPostRequestContract |
MGCLatticeGeneralLedgerJournalService | reverseJournal | MGCLatticeJournalReversalRequestContract |
MGCLatticeJournalPostingService | postLedgerJournal | MGCLatticeLedgerJournalPostingRequestContract |
MGCLatticeJournalPostingService | postInventoryJournal, postProjectJournal, postProductionJournal | MGCLatticeJournalPostingRequestContract |
MGCLatticeJournalPostingService | postTradeAgreementJournal | MGCLatticeTradeAgreementJournalPostingRequestContract |
MGCLatticeBudgetRegisterService | postBudgetEntry, postBudgetTransfer | MGCLatticeBudgetEntryPostRequestContract |
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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Correlation ID | CorrelationId | string (GUID) | No | Echoed when the query is refused |
| Tracking ID | TrackingId | string (GUID) | Yes | The 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.
| Field | JSON Key | Type | Description |
|---|---|---|---|
| Success | Success | boolean | true when the tracking ID was valid and the operation was found |
| Tracking ID | TrackingId | string (GUID) | The tracking record's id (all zeros when the request was refused before lookup) |
| Status | Status | MGCLatticeAsyncOperationStatus | Emitted as the enum's integer value: 0 None (refused query), 1 Queued, 2 Processing, 3 Succeeded, 4 Failed, 7 NotFound |
| Error Code | ErrorCode | MGCLatticeServiceErrorCode | For a Failed operation, the code of its failure; for a refused query ValidationFailed; for an unknown tracking ID DocumentNotFound; otherwise None |
| Is Retryable | IsRetryable | boolean | true when the failure was a transient runtime fault |
| Message | Message | string | The inner operation's message once terminal; otherwise empty, or the reason the query was refused |
| Errors | Errors | string[] | The inner operation's error messages once Failed, or the reason the query was refused |
| Document ID | DocumentId | string | The inner operation's document id once Succeeded |
| Posted Document ID | PostedDocumentId | string | The number of the document the inner operation produced (for a GL post, the posted journal number) once Succeeded |
| Submitted | SubmittedDateTimeUtc | datetime | When the tracking record was created |
| Completed | CompletedDateTimeUtc | datetime | 1900-01-01T00:00:00Z until the operation is terminal |
| Correlation ID | CorrelationId | string (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
RequestPayloadwithFormJsonSerializer::deserializeObject, which fills aListdata member only when the member declaresDataCollectionAttribute(AifCollectionTypeAttributealone 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Dimension Name | DimensionName | string | Yes | Financial dimension name (e.g., Department, CostCenter) |
| Dimension Value | DimensionValue | string | Yes | Dimension 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).
| Artifact | Type | Purpose |
|---|---|---|
MGCLatticeSalesOriginDimensionParameters | Table (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 |
MGCLatticeSalesOriginDimensionMap | Table + grid form (also holds the stamping switch) | Maps a SalesTable.SalesOriginId value to a target dimension name + value (unique per origin) |
MGCLatticeSalesOriginDimensionStamper | Class | Merges the mapped dimension value into the order's DefaultDimension using the standard DimensionAttributeValueSetStorage merge idiom |
MGCLatticeSalesOriginDimension_SalesTable_EventHandler | Data event handler | On 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
- The Process Automation Framework polls on a configurable interval (default: 60 seconds).
MGCLatticeAsyncOperationProcessAutomationTaskqueries theMGCLatticeAsyncOperationTrackingtable for records with Status =Queued.- For each queued record, it creates an
MGCLatticeAsyncOperationProcessorinstance. - 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
Succeededwith 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
Processingand less than 60 minutes old: the operation is still running and is left alone. - Otherwise (no inner
RequestId, a claimProcessingfor more than 60 minutes, or no claim when the operation was already queued again once): it is set toFailedand parked in the dead-letter queue for manual review with error codeRequestNeedsReview. Check the target documents before replaying it.
Supported Operations for Async Processing
| Service | Operations |
|---|---|
MGCLatticeFixedAssetService | runDepreciationProposal, postAcquisition, postDisposal, postAssetTransaction |
MGCLatticeCurrencyRevaluationService | runCustomerRevaluation, runVendorRevaluation, runLedgerRevaluation |
MGCLatticeInventoryCostService | activatePendingPrices, calculateItemCosts |
MGCLatticeGeneralLedgerJournalService | postGeneralJournal, postIntercompanyJournal, reverseJournal |
MGCLatticeJournalPostingService | postLedgerJournal, postInventoryJournal, postProjectJournal, postProductionJournal, postTradeAgreementJournal |
MGCLatticeBudgetRegisterService | postBudgetEntry, 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) | Polled | Creates a batch job |
|---|---|---|
Lattice dead-letter retry (MGCLatticeIntegrationDlqRetryBatch) | Every 5 minutes | When a Retrying dead letter is due or a Requeued one exists (hasDueWork) |
Lattice idempotency reconciliation (MGCLatticeIdempotencyReconciliationSweep) | Hourly | When a self-describing claim has been Processing for over 60 minutes (hasCandidates) |
Lattice business event reconciliation (MGCLatticeBusinessEventReconciliationSweep) | Hourly | When a failed, unreconciled event with retries left is at least 15 minutes old (hasCandidates) |
Lattice workflow stalled or failed alerts (MGCLatticeWorkflowStalledAlertBatch) | Hourly | Every poll |
Lattice service call statistics rollup (MGCLatticeServiceCallStatisticsRollup) | Daily | Every poll |
Lattice integration log cleanup (MGCLatticeServiceLogCleanup) | Daily | Every poll |
Lattice file ingestion cleanup (MGCLatticeFileIngestCleanup) | Daily | Every poll |
Lattice sales price effectivity events (MGCLatticeTradeAgreementPriceEffectivityBatch) | Daily | Every poll |
| Artifact | Type | Purpose |
|---|---|---|
MGCLatticeMaintenanceAutomation | Class | The definitions: type names, labels, polling patterns, the work check (hasWork, workList) and newJob / runJob |
MGCLattice*AutomationTypeRegistration, MGCLattice*AutomationSeriesRegistration | Classes (16) | One type and one series registration per process (ProcessScheduleITypeRegistration, ProcessScheduleISeriesRegistration), delegating to MGCLatticeMaintenanceAutomation |
MGCLatticeMaintenanceAutomationTask | Class (ProcessAutomationTask) | The one task of all eight types; returns the work of the type it was polled for |
MGCLatticeMaintenanceAutomationController | Class (SysOperationServiceController) | The batch task; its data contract is the polled ProcessScheduleWorkItem |
MGCLatticeMaintenanceAutomationService | Class | runTask 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.
| Table | Aged by | Default retention | Notes |
|---|---|---|---|
MGCLatticeServiceCallLog | StartDateTimeUtc | 90 days | Every 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 |
MGCLatticeServiceCallStatistics | StatisticsDate | 90 days (call log window) | Daily rollups |
MGCLatticeFileIngestLog | system createdDateTime | 90 days | Diagnostic ingestion log |
MGCLatticeServiceIdempotencyLog | CompletedDateTimeUtc | 30 days | Only 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 |
MGCLatticeAsyncOperationTracking | SubmittedDateTimeUtc | 30 days | Succeeded and Failed rows only |
MGCLatticeIntegrationDeadLetter | LastAttemptDateTimeUtc | 90 days | Reprocessed and Discarded rows only; open (Retrying, Parked, Held) and Requeued rows are kept |
MGCLatticeBusinessEventLog | system createdDateTime | 90 days | Success 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.
| Enum | Members (numeric) | Role |
|---|---|---|
MGCLatticeDocReconcileOutcome | NotFound (0), CreatedNotPosted (1), Posted (2) | Result of a handler probing for the created document |
MGCLatticeIdempotencyReconcileState | NotReconciled (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).
| Entity | Collection Name | Backing Table | Description |
|---|---|---|---|
MGCLatticeServiceCallLogEntity | LatticeServiceCallLogs | MGCLatticeServiceCallLog | One 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). |
MGCLatticeServiceCallStatisticsEntity | LatticeServiceCallStatistics | MGCLatticeServiceCallStatistics | Daily 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. |
MGCLatticeServiceIdempotencyLogEntity | LatticeServiceIdempotencyLogs | MGCLatticeServiceIdempotencyLog | Claim-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. |
MGCLatticeAsyncOperationTrackingEntity | LatticeAsyncOperationTrackingRecords | MGCLatticeAsyncOperationTracking | One 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
Statusproperty onMGCLatticeServiceCallLogEntityandMGCLatticeServiceIdempotencyLogEntity(MGCLatticeServiceCallStatus) and onMGCLatticeAsyncOperationTrackingEntity(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 toErrorCode(MGCLatticeServiceErrorCode),ReconcileState(MGCLatticeIdempotencyReconcileState), and theNoYesflagsSuccessandIsPreview, which serialize as"Yes"or"No"and are filtered asIsPreview 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.
| Value | Numeric | Description |
|---|---|---|
None | 0 | Unset / default |
Queued | 1 | Staged, awaiting processing (a worker claims it under a row lock; there is no in-progress state) |
Processed | 3 | Successfully transformed and dispatched |
Failed | 4 | Exceeded the retry cap |
Held | 6 | Held by an operator on the bundle inquiry; the segment processor skips it until it is released back to Queued |
MGCLatticeFileIngestStorageType - cloud source type.
| Value | Numeric | Description |
|---|---|---|
Blob | 0 | Azure Blob storage |
FileShare | 1 | Azure File share |
Sftp | 2 | SFTP server |
MGCLatticeFileIngestFileFormat - inbound file format / parser selector.
| Value | Numeric | Description |
|---|---|---|
Xml | 0 | XML; records identified by an element name or element path; each record is converted to JSON before the Liquid transform |
Json | 1 | JSON; records identified by a JSON path |
Csv | 2 | CSV / 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. |
FixedWidth | 3 | Fixed-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.
| Value | Numeric | Description |
|---|---|---|
None | 0 | Not set: no secret is stored |
Encrypted | 1 | AuthSecret holds the secret, encrypted with the platform encryption service |
KeyVaultReference | 2 | AuthSecretKvRef 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.
| Field | Type | Description |
|---|---|---|
ConnectionId | string(60) | Unique connection identifier (mandatory, PK) |
Name | string(100) | Friendly description |
StorageType | enum MGCLatticeFileIngestStorageType | Source storage type |
Endpoint | string(255) | Storage endpoint / host (may also be supplied in the secret JSON) |
ContainerOrShare | string(255) | Blob container or file-share name; for SFTP the remote root path that relative paths are resolved under (blank: the login directory) |
FolderPath | string(255) | Sub-path within the container/share/SFTP root to scan; for SFTP a path that starts with / is used as is |
FilePattern | string(100) | Filename wildcard filter (e.g. *.xml) |
AuthSecret | container (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. |
AuthSecretKvRef | string(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. |
ArchiveFolderPath | string(255) | Folder an ingested source file is moved to; blank deletes it |
ErrorFolderPath | string(255) | Folder a file that cannot be ingested is moved to; blank leaves it in place |
FileFormat | enum MGCLatticeFileIngestFileFormat | Inbound file format |
RecordPath | string(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 / CsvQuoteChar | string / enum NoYes / string | CSV 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) |
FixedWidthColumnSpec | DirMemo | JSON array of {"name","start","width"} column definitions for FixedWidth (required for that format; exactly these keys, start 0-based, width above 0, whole numbers) |
TargetServiceClass | string(255) | X++ class that receives transformed records; must implement MGCLatticeIFileIngestServiceTarget |
TargetServiceOperation | string(80) | Method on the target class invoked per record with the transformed content as its one str argument |
LiquidTemplate | DirMemo | Liquid transform applied to each record (as JSON); blank sends the JSON record unchanged |
Enabled | enum NoYes | Only enabled connections are scanned by the pull job |
MaxFilesPerRun | int | The most files the pull ingests for the connection in one run; 0 means no limit |
RetentionDays | int | Days 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 |
MinFileAgeSeconds | int (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. |
AllowedServiceOperations | DirMemo | Allowed 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. |
RequireStableSize | enum NoYes | Wait 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:
| Method | Signature | Description |
|---|---|---|
setAuthSecret | void 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. |
editAuthSecret | edit 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. |
authSecretStorage | display MGCLatticeFileIngestSecretStorage authSecretStorage() | Display method behind the Secret storage field. |
insert / update | void insert() / void update() | Run the platform's encrypted-table hooks around the save. |
validateField | boolean 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.
| Field | Type | Description |
|---|---|---|
ConnectionId | string | The connection the lease is for |
LockOwner | GUID | The run that holds the lease |
LockedUntilUtc | utcdatetime | When 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.
| Field | Type | Description |
|---|---|---|
ConnectionId | string | The connection |
SourceFileName | string(1024) | The source file's full path |
SourceFileNameHash | string(44) | Base64 SHA-256 of the path (part of the key) |
SizeBytes | int64 | The size seen on the last run |
ObservedDateTimeUtc | utcdatetime | When 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.
| Field | Type | Description |
|---|---|---|
BundleId | string(60) | Bundle identifier (PK) |
ConnectionId | string | Owning connection |
SourceFileName | string(1024) | The source file's full path (a longer path is refused) |
ClaimDocuRefId | int64 | RecId of the DocuRef holding the claim-checked file (document type DocuType::typeFile()) |
FileSizeBytes | int64 | File size in bytes |
SegmentCount | int | Number of segments produced from the file |
ReceivedDateTime | utcdatetime | When 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.
| Field | Type | Description |
|---|---|---|
BundleId | string | Owning bundle |
Sequence | int | Position of the record within the file |
RawContent | DirMemo | Extracted record content as received (an XML record stays XML; JSON, CSV and fixed-width records are JSON) |
TransformedContent | DirMemo | Liquid-rendered payload sent to the target |
State | enum MGCLatticeFileIngestState | Per-segment processing state |
ProcessingAttempts | int | Number of processing attempts (retried until the cap of 3) |
NextAttemptDateTime | utcdatetime | When a retried segment becomes eligible again |
ErrorCode / ErrorCategory | enum | Classified error of the last failure |
ErrorMessage | DirMemo | Last error message, if any |
RequestId | GUID | The 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).
| Field | Type | Description |
|---|---|---|
LogLevel | enum MGCLatticeLogLevel | Severity (Info, Warning, Error) |
ConnectionId | string | Related connection |
BundleId | string | Related bundle |
SegmentId | int64 | Related segment (its RecId) |
Message | DirMemo | Log message |
Details | DirMemo | Additional 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).
| Field | Type | Description |
|---|---|---|
ConnectionId | string | Owning connection (part of the dedup key) |
SourceFileName | string(1024) | The source file's full path |
SourceFileNameHash | string(44) | Base64 SHA-256 of the full path (part of the dedup key) |
FileHash | string(44) | Base64-encoded SHA-256 hash of the file content (part of the dedup key) |
BundleId | string | The 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.
| Method | Signature | Description |
|---|---|---|
construct | static MGCLatticeFileIngestPull construct() | Factory |
description | static ClassDescription description() | RunBase caption |
run | void run() | Executes the pull |
main | static void main(Args _args) | Menu-item entry point |
pack / unpack | container 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.
| Class | Method | Signature | Description |
|---|---|---|---|
| Controller | construct | static MGCLatticeFileIngestSegmentController construct() | Factory |
| Controller | main | static void main(Args _args) | Entry point |
| Service | construct | static MGCLatticeFileIngestSegmentService construct() | Factory |
| Service | isRetryable | boolean isRetryable() | Returns true (BatchRetryable contract) |
| Service | processSegments | void processSegments() | Top-picking drain loop |
| Service | recordJson | static 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 |
| Service | transformRecord | static 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.
| Method | Signature | Description |
|---|---|---|
construct | static MGCLatticeFileIngestCleanup construct() | Factory |
canRunInNewSession | boolean canRunInNewSession() | Batch session support |
run | void run() | Executes the cleanup |
main | static 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.
| Class | Method | Signature | Description |
|---|---|---|---|
| Parser (abstract) | parmRecordPath | str parmRecordPath(str _recordPath = recordPath) | Gets/sets the record path |
| Parser (abstract) | parseRecords | abstract List parseRecords(str _content) | Splits file content into per-record fragments |
| Xml | recordXPath | static 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 |
| Xml | isValidRecordPath | static boolean isValidRecordPath(str _recordPath) | True when every step is an XML element name (no predicates, attributes, wildcards or prefixes); blank is valid |
| Json | recordPathError | static str recordPathError(str _recordPath) | Empty when the JSON path is valid (or blank); otherwise the parser's reason |
| Csv | parmDelimiter / parmHasHeader / parmQuoteChar | str parmDelimiter(str), NoYes parmHasHeader(NoYes), str parmQuoteChar(str) | Delimited settings; the defaults are comma, header row and double quote |
| FixedWidth | parmColumnSpec | str parmColumnSpec(str _columnSpec = columnSpec) | The {name,start,width} column specification; parsing without one throws |
| Factory | construct | static MGCLatticeFileIngestParser construct(MGCLatticeFileIngestFileFormat _format, str _recordPath) | Returns the parser for the format with the record path set and no connection settings |
| Factory | constructForConnection | static 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.
| Class | Method | Signature | Description |
|---|---|---|---|
| Dispatcher (abstract) | dispatch | abstract boolean dispatch(str _transformedContent, MGCLatticeFileIngestConnection _connection, str _bundleId, int64 _segmentId) | Delivers a transformed payload; returns true on success |
| Factory | construct | static MGCLatticeFileIngestDispatcher construct(MGCLatticeFileIngestConnection _connection) | Returns the dispatcher for the connection |
MGCLatticeFileIngestLogger
Helper that writes MGCLatticeFileIngestLog records.
| Method | Signature | Description |
|---|---|---|
construct | static MGCLatticeFileIngestLogger construct() | Factory |
log | static 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).
| Method | Signature | Description |
|---|---|---|
resolveConnectionSecret | static 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. |
storage | static MGCLatticeFileIngestSecretStorage storage(MGCLatticeFileIngestConnection _conn) | Encrypted, KeyVaultReference or None. |
isKeyVaultReference | static 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
| Form | Purpose |
|---|---|
MGCLatticeFileIngestConnection | Setup 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 |
MGCLatticeFileIngestBundleInquiry | Read-only monitor: bundles → segments (with their request ID) → log |
MGCLatticeLiquidTester | Diagnostic 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
| Artifact | Type | Grants |
|---|---|---|
MGCLatticeFileIngestMaintain | Privilege | Maintain connections (Create/Read/Update/Delete on the connection menu item) and Invoke the pull, segment processor, and cleanup actions |
MGCLatticeFileIngestView | Privilege | Read-only access to the bundle inquiry monitor |
MGCLatticeFileIngestOperationsView | Privilege | Read-only access to the file ingestion operations workspace and its list parts |
MGCLatticeFileIngestDuty | Duty | Bundles the three privileges above (MGCLatticeFileIngestMaintain, MGCLatticeFileIngestView, MGCLatticeFileIngestOperationsView) |
MGCLatticeFileIngestSimulatorDuty | Duty | Bundles 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).
| Method | Signature | Description |
|---|---|---|
ListFiles | string[] ListFiles(string storageType, string connectionJson, string path, string pattern) | Lists files at the location matching the wildcard pattern (empty pattern matches all) |
DownloadToString | string DownloadToString(string storageType, string connectionJson, string path) | Downloads a file and returns its contents decoded as UTF-8 (for small to moderate files) |
DownloadToTempFile | string 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 |
DeleteFile | bool DeleteFile(string storageType, string connectionJson, string path) | Deletes a file if it exists; returns true when a file was deleted |
MoveFile | void 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 |
GetFileAgeSeconds | long 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. |
GetFileSizeBytes | long 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 |
ExtractRoutedOperations | static 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. |
RenderTemplate | string RenderTemplate(string templateText, string jsonData) | Renders a Liquid template against JSON data (delegates to LiquidTransformer) |
ConvertXmlToJson | string 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 / ConvertFixedWidthToJson | string 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 |
ValidateStrictJson | string 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 |
ResolveKeyVaultSecret | string 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. |
IsKeyVaultSecretUri | static 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} |
DecryptSourceFile | byte[] 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).
| Member | Signature | Description |
|---|---|---|
ListFiles | IEnumerable<string> ListFiles(string path, string pattern) | Enumerates matching file names (lazily where supported) |
OpenRead | Stream OpenRead(string path) | Opens a forward-only read stream (caller disposes) |
DeleteFile | bool DeleteFile(string path) | Deletes the file if it exists |
CloudFileSourceFactory.Create | static 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.
| Method | Signature | Description |
|---|---|---|
Render | string 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.
| Field | Type | Description |
|---|---|---|
EntityName | string | Data entity (AOT) name (PK) |
PublicCollectionName | string | OData collection name (the /data/{name} set) |
PublicEntityName | string | OData singular public entity name |
EntityTable | string | Backing table: the table of the root data source of the entity |
EntityCategory | enum EntityCategory | Entity category |
SysModule | enum DMFModule | Owning module (System administration when the entity names a module that DMFModule does not have) |
Tags | string | Entity tags |
IsObsolete | enum NoYes | Marked obsolete |
Description | string | Description |
PackageName | string | Owning package/model |
IsCustom | enum NoYes | Custom (non-Microsoft) entity |
IsPublic | enum NoYes | Exposed as a public OData entity |
IsReadOnly | enum NoYes | The entity is read-only |
PrimaryKey | string | The fields of the entity key, comma-separated in key order |
ContentHash | string | Hash of the entity's metadata signature (entity, fields, methods); a refresh rewrites the entity only when it changed |
FieldCount | int | Number of fields |
MethodCount | int | Number of exposed methods |
MGCLatticeODataFieldMetadata
One record per field on an entity. Index EntityFieldIdx; relation to MGCLatticeODataEntityMetadata.
| Field | Type | Description |
|---|---|---|
EntityName | string | Owning entity |
FieldName | string | Field name |
DataType | string | Base data type |
ExtendedDataType | string | EDT, if any |
EnumType | string | Enum type, if any |
Label | string | Field label |
IsMandatory | enum NoYes | Field is mandatory |
IsKey | enum NoYes | Field participates in the entity key |
AllowEdit | enum NoYes | Field is editable |
IsObsolete | enum NoYes | Field is marked obsolete |
Position | int | Ordinal 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.
| Field | Type | Description |
|---|---|---|
EntityName | string | Owning entity |
MethodName | string | X++ method name |
ODataActionName | string | OData action/function name |
IsBound | enum NoYes | Whether the action is bound to the entity |
ReturnType | string | Return type |
ParameterCount | int | Number of parameters |
SampleRequestJson | string | Generated sample request body |
SampleResponseJson | string | Generated sample response body |
MGCLatticeODataEntityMethodParameter
One record per parameter of an exposed method. Index MethodParamIdx; relation to MGCLatticeODataEntityMethod.
| Field | Type | Description |
|---|---|---|
EntityName | string | Owning entity |
MethodName | string | Owning method |
ParameterName | string | Parameter name |
Position | int | Ordinal position |
DataType | string | Parameter data type |
ContractClassName | string | Data contract class, when the parameter is a contract |
IsContract | enum NoYes | Whether 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.
| Field | Type | Description |
|---|---|---|
LogLevel | enum MGCLatticeLogLevel | Severity (Info, Warning, Error) |
EntityName | string | Related entity (clamped to 255 chars by the logger) |
FieldName | string | Related field (clamped to 255 chars by the logger) |
Message | string | Log message, including the failing step for error rows |
Details | string | Additional 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.
| Method | Signature | Description |
|---|---|---|
construct | static MGCLatticeODataMetadataDiscovery construct() | Factory |
refreshAll | static 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 |
logRunError | static 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 captureCLRInterop::getLastException().ToString()inDetails; 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-leveltry/catch(outside any transaction) that logs anErrorrow 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/FieldNamecolumns and never throws, so a logging failure can never mask the original exception being recorded. - Summary counters. Each stage emits an
Infosummary 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 asWarningrows naming the field.
MGCLatticeODataMetadataRefreshBatch
Extends RunBaseBatch. Wraps MGCLatticeODataMetadataDiscovery::refreshAll() so the refresh can be scheduled as a batch job.
| Method | Signature | Description |
|---|---|---|
construct | static MGCLatticeODataMetadataRefreshBatch construct() | Factory |
run | void 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 |
description | static ClassDescription description() | RunBase caption |
main | static void main(Args _args) | Entry point |
pack / unpack | container pack() / boolean unpack(container _packedClass) | RunBase state persistence |
26.4 Form
| Form | Purpose |
|---|---|
MGCLatticeODataEntityMetadataExplorer | Workspace to browse discovered entities, their fields, methods, parameters, and generated sample payloads; includes a refresh action |
26.5 Security
| Artifact | Type | Grants |
|---|---|---|
MGCLatticeODataEntityMetadataExplorerPrivilege | Privilege | Read access to the explorer form and Invoke/Read/Delete on the metadata refresh action |
MGCLatticeODataEntityMetadataExplorerDuty | Duty | Bundles 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:
| Generator | Method | Output |
|---|---|---|
ODataPostmanGenerator | static string Generate(ODataMetadataExport metadata) | Postman v2.1 collection JSON |
ODataOpenApiGenerator | static string Generate(ODataMetadataExport metadata) | OpenAPI 3.0.3 specification JSON |
DocumentationService provides OData-specific entry points (in addition to its service-metadata methods):
| Method | Signature | Description |
|---|---|---|
GenerateODataPostmanFromJson | string GenerateODataPostmanFromJson(string odataMetadataJson) | Postman collection from an OData metadata JSON payload |
GenerateODataOpenApiFromJson | string GenerateODataOpenApiFromJson(string odataMetadataJson) | OpenAPI spec from an OData metadata JSON payload |
GenerateODataPostmanFromJson | string GenerateODataPostmanFromJson(string odataMetadataJson, string packageFilter) | As above, restricted to entities whose PackageName matches packageFilter (case-insensitive) |
GenerateODataOpenApiFromJson | string 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Correlation ID | CorrelationId | GUID | No | Echoed on the response for distributed tracing |
| Legal Entity | LegalEntityId | string | No | Company to resolve the price in; empty uses the caller's current company. A company that does not exist is refused (ValidationFailed). |
| Customer Account | CustAccount | string | Yes | Customer whose price group drives the agreement search |
| Item ID | ItemId | string | Yes | Item to price |
| Customer Account key | CustAccountExternalKey | string | No | The customer's alternate key in ExternalSystem, used in place of CustAccount. |
| Item ID key | ItemIdExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemId. |
| External System | ExternalSystem | string | No | The 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. |
| Quantity | Qty | decimal | No | Quantity break to evaluate (defaults to 1) |
| Price Date | PriceDate | date | No | Effective date (defaults to today's date in the calling user's time zone) |
| Currency Code | CurrencyCode | string | No | Currency (defaults to the customer currency) |
| Unit ID | UnitId | string | No | Unit of measure (defaults to the item's sales unit) |
| Site | SiteId | string | No | Site dimension for site-specific agreements |
| Warehouse | WarehouseId | string | No | Warehouse 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):
| Field | JSON Key | Type | Description |
|---|---|---|---|
| Success | Success | boolean | Whether the inquiry executed without error |
| Message | Message | string | Result / error text |
| Correlation ID | CorrelationId | GUID | The request's correlation id |
| Error Code | ErrorCode | integer | MGCLatticeServiceErrorCode (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. |
| Errors | Errors | string[] | The error lines the inquiry raised; empty on success |
| Price Found | PriceFound | boolean | true when an agreement or base price resolved |
| Unit Price | UnitPrice | decimal | Resolved effective price |
| Price Unit | PriceUnit | decimal | Price-per quantity basis (e.g. price per 100) |
| Source Agreement RecId | SourceAgreementRecId | integer | RecId of the winning PriceDiscTable row; 0 means the item base price was used |
| Applied Currency Code | AppliedCurrencyCode | string | Currency actually applied |
| Applied Date | AppliedDate | date | Date actually applied |
| Applied Quantity | AppliedQty | decimal | Quantity 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)
| Value | Numeric | Description |
|---|---|---|
None | 0 | No outcome (never returned by a completed call) |
Created | 1 | A new price row was inserted (a complex timeline with FindNext true, for example the first price for a key) |
EditedInPlace | 2 | An existing same-FromDate row was updated |
Superseded | 3 | A prior row was capped and a new row added |
RejectedComplex | 4 | The existing timeline was too complex to change safely; nothing was created |
Unchanged | 5 | The requested price is already effective; nothing changed |
Failed | 6 | The 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Correlation ID | CorrelationId | GUID | No | Echoed on the result for tracing |
| Legal Entity | LegalEntityId | string | No | Company to post the agreement in; empty uses the caller's current company. A company that does not exist is refused (ValidationFailed). |
| Account Code | AccountCode | integer (enum PriceDiscPartyCodeType) | Yes | Party scope, sent as a number: 0 Table (customer), 1 GroupId (price group), 2 All. The name ("Table") is refused with HTTP 400. |
| Account Relation | AccountRelation | string | Yes | Customer account or price group (per AccountCode). With AccountCode 0 the customer must exist (DocumentNotFound otherwise). |
| Item Code | ItemCode | integer (enum PriceDiscProductCodeType) | Yes | Product scope, sent as a number: 0 Table (item), 1 GroupId (item group), 2 All. |
| Item Relation | ItemRelation | string | Yes | Item number or item group (per ItemCode). With ItemCode 0 the item must exist (DocumentNotFound otherwise). |
| Account Relation key | AccountRelationExternalKey | string | No | The customer's alternate key in ExternalSystem, used in place of AccountRelation. Only with AccountCode = Table; refused otherwise. |
| Item Relation key | ItemRelationExternalKey | string | No | The released product's alternate key in ExternalSystem, used in place of ItemRelation. Only with ItemCode = Table; refused otherwise. |
| External System | ExternalSystem | string | No | The 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 Code | CurrencyCode | string | Yes | Agreement currency |
| Unit ID | UnitId | string | No | Unit of measure; empty defaults to the item's sales unit when ItemCode is 0 (Table) |
| From Quantity | FromQty | decimal | No | Quantity break "from" (0 = all quantities) |
| Unit Price | UnitPrice | decimal | Yes | Unit 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 Price | AllowZeroPrice | boolean | No | true to set a unit price of zero (a free item) |
| Price Unit | PriceUnit | decimal | No | Price-per quantity basis (defaults to 1) |
| From Date | FromDate | date | Yes | Effective-from date (drives edit-vs-supersede); not earlier than today in the calling user's time zone |
| To Date | ToDate | date | No | Effective-to date (empty = open-ended) |
| Find Next | FindNext | boolean | No | true 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 |
| Site | SiteId | string | No | Site dimension |
| Warehouse | WarehouseId | string | No | Warehouse dimension |
| Preview Mode | PreviewMode | boolean | No | setSalesPrice has no preview: true is refused with ErrorCode PreviewUnsupported before anything runs |
Result Contract: MGCLatticeSetSalesPriceResult
| Field | JSON Key | Type | Description |
|---|---|---|---|
| Success | Success | boolean | true for Created, EditedInPlace, Superseded and Unchanged; false for RejectedComplex and Failed |
| Message | Message | string | Result / error text |
| Correlation ID | CorrelationId | GUID | The request's correlation id |
| Error Code | ErrorCode | integer | MGCLatticeServiceErrorCode; 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 |
| Errors | Errors | string[] | The error lines raised; empty on success |
| Outcome | Outcome | integer | MGCLatticeTradeAgreementOutcome numeric value |
| Outcome Name | OutcomeName | string | MGCLatticeTradeAgreementOutcome member name |
| Journal Number | JournalNum | string | Price/discount journal the agreement was posted under |
| Created Agreement RecId | CreatedAgreementRecId | integer | RecId of the newly created PriceDiscTable row |
| Superseded Agreement RecId | SupersededAgreementRecId | integer | RecId of the capped (superseded) row, if any |
| Superseded New To Date | SupersededNewToDate | date | The new ToDate stamped on the superseded row |
| Applied From Date | AppliedFromDate | date | Effective-from date actually applied |
| Applied To Date | AppliedToDate | date | Effective-to date actually applied |
| Applied Unit Price | AppliedUnitPrice | decimal | Unit 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:
| Field | JSON Key | Type | Description |
|---|---|---|---|
| Success | Success | boolean | true when the list has items and every item succeeded |
| Message | Message | string | Summary ("N of M sales prices were applied.") or why the batch was refused |
| Total Count | TotalCount | integer | Number of request items |
| Success Count | SuccessCount | integer | Items that succeeded |
| Failure Count | FailureCount | integer | Items that failed |
| Results | Results | MGCLatticeSetSalesPriceResult[] | 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 class | Fires when |
|---|---|
MGCLatticeTradeAgreementPriceCreatedBusinessEvent | a 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 |
MGCLatticeTradeAgreementPriceModifiedBusinessEvent | a posted journal line changes at least one value of an existing sales price; the payload lists the changed fields |
MGCLatticeTradeAgreementPriceSupersededBusinessEvent | a 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 |
MGCLatticeTradeAgreementPriceDeletedBusinessEvent | a sales price is deleted by a user, by code, or by a posted journal line marked for deletion |
MGCLatticeTradeAgreementPriceEffectiveBusinessEvent | the effectivity batch reports, once and in date order, each sales price whose From date has been reached |
MGCLatticeTradeAgreementPriceExpiredBusinessEvent | the 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
Activewith its expiry moved to now, and the expiry sweep revokes it.
Request Contract: MGCLatticeDbAccessRequestContract
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Correlation ID | CorrelationId | string (GUID) | No | Echoed on the response |
| IP Address | IpAddress | string | Yes | Public IPv4 address to allowlist on the AxDB firewall |
| Duration Hours | DurationHours | integer | No | Grant lifetime; defaults to 24, clamped to 1-72 |
Response Contract: MGCLatticeDbAccessResponseContract
| Field | JSON Key | Type | Description |
|---|---|---|---|
| Correlation ID | CorrelationId | string (GUID) | Echoed from the request |
| Success | Success | boolean | Whether the request succeeded |
| Error Code | ErrorCode | MGCLatticeServiceErrorCode | Why 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 |
| Message | Message | string | Non-sensitive result message |
| Username | Username | string | Provisioned contained database user name |
| Password | Password | string | Generated password - populated only on this live response; never persisted in cleartext or logged |
| Server Name | ServerName | string | AxDB server host to connect to (Azure SQL Database reports a short name; the response carries the full <server>.database.windows.net) |
| Database Name | DatabaseName | string | AxDB database to connect to |
| Expires | ExpiresDateTimeUtc | datetime | When 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
| Field | JSON Key | Type | Required | Description |
|---|---|---|---|---|
| Correlation ID | CorrelationId | string (GUID) | No | Echoed on the response |
{
"_request": {
"CorrelationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
}
The grant lifecycle is completed by
MGCLatticeDbAccessExpiryBatch(action menu itemMGCLatticeDbAccessExpiry), which revokes every active grant past its expiry, including grants whose revoke failed, marks themExpiredand clears their stored password. There is no permanent recurring job: before a grant is issued,MGCLatticeDbAccessExpiryBatch::ensureScheduledschedules 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 (ErrorCodeAccessDenied). 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)
| Value | Numeric | Description |
|---|---|---|
None | 0 | The response is not a preview (every normal call) |
ValidationOnly | 1 | The request was validated as a preview; nothing was posted |
| Artifact | Type | Purpose |
|---|---|---|
MGCLatticeIPreviewableRequest | Interface | Implemented by request contracts whose operation runs a preview; carries the PreviewMode member |
MGCLatticeServiceCallLog.IsPreview | Field | Marks 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.
| Artifact | Type | Purpose |
|---|---|---|
MGCLatticeServiceTestConsole | Form | Pick 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) |
MGCLatticeServiceTestRunner | Class | Reflection invoker (SysDictClass::callObject + FormJsonSerializer) that deserializes the request JSON, calls the operation, and serializes the response |
MGCLatticeServiceTestRequest / MGCLatticeServiceTestResult | Tables / contracts | Saved 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)
| Value | Numeric | Description |
|---|---|---|
All | 0 | Persist a call-log row for every call |
ErrorsOnly | 1 | Persist a row only when the call fails |
Off | 2 | Persist nothing for this operation |
| Artifact | Type | Purpose |
|---|---|---|
MGCLatticeServiceOperationLogConfig | Table | Per-operation logging level (service + operation → level); the operation is the recorded operation name (see 24. OData Monitoring Entities) |
MGCLatticeServiceLoggingPolicy | Class | Resolves the effective level and gates call-log persistence in MGCLatticeOrderPostingServiceBase.recordCompletion |
MGCLatticeServiceCallStatistics | Table | Aggregated per-operation call counts, timings, and failure counts |
MGCLatticeServiceCallStatisticsRollup | Class (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.
| Artifact | Type | Purpose |
|---|---|---|
MGCLatticeIntegrationDeadLetter | Table | One 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 |
MGCLatticeIntegrationDlqManager | Class | enqueue (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) |
MGCLatticeIntegrationDlqRetryBatch | Batch class | Auto-retry sweep (below) |
MGCLatticeIntegrationDlqEditReplay | Form | Edit the payload of a dead-letter row and resubmit it |
MGCLatticeIntegrationDlqStatus / MGCLatticeIntegrationDlqSource | Enums | Row 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)
| Value | Numeric | Description |
|---|---|---|
Pending | 0 | Marked on insert; awaiting evaluation |
Held | 1 | Price outside tolerance and the standard price hold (HoldCode) is on the order; waits for that hold to be cleared |
AutoConfirmed | 2 | Confirmed automatically by the policy |
Processed | 3 | Evaluation complete, left for the user |
Released | 4 | The standard price hold was cleared or removed; awaiting the next evaluation run |
Flagged | 5 | Price outside tolerance but no standard hold was placed (no PriceHoldCode, or the feature off); not auto-confirmed, not evaluated again |
| Artifact | Type | Purpose |
|---|---|---|
MGCLatticeInboundOrderPolicyParameters | Table (one row per legal entity) + form | Master switch PolicyEnabled (default Off), price-tolerance percent, and related settings |
MGCLatticeInboundOrderPolicyState | Table | Per-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 |
MGCLatticeInboundOrderGuardrailPolicy | Class | The evaluation engine |
MGCLatticeInboundOrderPolicyEvaluationBatch | Class (RunBaseBatch) + menu item | Evaluates 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 handlers | Data event handlers | Mark new orders Pending on insert; enforce the post-confirm edit-lock via validating-write/-delete |
MGCLatticeMCRHoldCodeTrans_Table_Extension | Table 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.
| Entity | Collection Name | Backing Table | Key | Description |
|---|---|---|---|---|
MGCLatticeRecurringDataJobEntity | LatticeRecurringDataJobs | IntegrationActivityTable | Name | The job: its data project, direction, schedule and state |
MGCLatticeRecurringDataJobClientEntity | LatticeRecurringDataJobClients | IntegrationClientMapTable | JobName + ClientId | A 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:
| Property | Type | Notes |
|---|---|---|
RecurrenceUnit | SysRecurrenceUnit | Minute, Hour, Day, Week, Month, Year |
RecurrenceInterval | int | Every N units |
RecurrenceStartDateTime | UTC datetime | First run |
RecurrenceEndType | MGCLatticeRecurrenceEndType | NotSet (0), NoEnd (1), EndAfterCount (2), EndByDate (3) |
RecurrenceEndAfterCount | int | With EndAfterCount |
RecurrenceEndDate | date | With EndByDate |
RecurrenceTimeZone | Timezone | The zone the schedule's clock times are read in |
MonitoringRecurrenceUnit, MonitoringRecurrenceInterval | The monitoring job's schedule; hourly by default | |
RecurrenceDescription | string, read-only | The recurrence rendered as the platform renders it |
BatchGroupId | string | Not 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.
| Action | Parameters | Returns |
|---|---|---|
Activate | _batchGroupId (string, blank for the default batch group) | A sentence describing the outcome |
Deactivate | none | A sentence describing the outcome |
POST {baseUrl}/data/LatticeRecurringDataJobs(Name='NightlyCustomerImport')/Microsoft.Dynamics.DataEntities.Activate
Content-Type: application/json
{ "_batchGroupId": "" }
Constraints worth knowing
| Constraint | Behavior |
|---|---|
| The data project must already exist | The 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 changed | The 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-only | Assigned by the platform. Name is the key. |
A job name with { or } cannot be activated | The platform's scheduler fails on such a name. Choose job names without braces. |
| Row-by-row processing | Activation happens in the row write path, so set-based processing must stay disabled for these entities. |
JobName on the client entity | A 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
| Operation | Purpose | Privilege |
|---|---|---|
captureSpec | Reads an environment's data projects and recurring data jobs as a specification | MGCLatticeDmfConfigServiceView |
specFromPackageManifest | Turns a data package's Manifest.xml into a specification | MGCLatticeDmfConfigServiceView |
diffSpec | Compares a specification with the environment, member by member, without changing it | MGCLatticeDmfConfigServiceView |
applySpec | Makes an environment match a specification | MGCLatticeDmfConfigServiceApply |
...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": []
}
| Member | Meaning |
|---|---|
Mode | Default (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. |
Overrides | Mapping 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. |
SourceFields | The 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. |
Conversions | Value conversions: StagingField, SourceField, FieldType, From, To. |
Transforms | The 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" }
]
}
| Flag | Effect |
|---|---|
ValidateOnly | Works out what would change and writes nothing. The plan step for a pull request. |
PruneMissing | Also 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": "" }
]
}
| Member | Meaning |
|---|---|
Differences | How many differences were found. Zero means the environment matches the specification. |
NotApplicable | How many of them applySpec cannot remove. |
Items | One 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
| Constraint | Behavior |
|---|---|
| An entity line can only name an entity in the data management entity list | Otherwise that line fails, naming the entity. After deploying new entities, refresh the entity list. |
EntityName is the data management display name | Customers, not CustCustomerV3Entity. |
| A data project name is capped at 60 characters, a job name at 40 | A 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 entity | The 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 written | They 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 in | A 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
| Operation | Purpose | Privilege |
|---|---|---|
validateMappings | Checks the field mappings of data projects and reports every problem. Read-only. | MGCLatticeDmfMappingServiceView (operations duty) |
refreshMappings | Adds missing mappings, removes mappings to fields that no longer exist and, on request, regenerates a stale staging-to-target mapping | MGCLatticeDmfMappingServiceMaintain (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 member | Type | Meaning |
|---|---|---|
DataProjectNamePattern | string | Data projects to check, as a pattern (Cust*, or * for every project). |
RecurringDataJobName | string | A 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.
| Check | Severity | Meaning |
|---|---|---|
ProjectNotFound | Error | The data project does not exist (for example a recurring data job pointing at a deleted project). |
NoMapping | Error | The entity has no source-to-staging mapping at all. |
KeyFieldUnmapped | Error | A mandatory key field of the staging table is neither mapped from a source field nor auto-generated. |
MandatoryFieldUnmapped | Error | (Import projects) a mandatory staging field is neither mapped, defaulted nor auto-generated. |
StagingFieldMissing | Error | A mapping points at a staging field that no longer exists. |
SourceFieldMissing | Error | (File sources) a mapping reads a source field that is not one of the entity's source fields. |
FieldNotMapped | Warning | A staging field the standard mapping generation maps has no mapping, typically a field added to the entity after the mapping was generated. |
TargetMappingStale | Warning | The 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 member | Type | Meaning |
|---|---|---|
DataProjectName | string | Required. The data project. |
EntityName | string | One entity of the project, by its data management name; blank for every enabled entity. |
RegenerateTargetMapping | boolean | Also regenerate the staging-to-target mapping of each entity whose mapping is stale. This changes it for every project that uses the entity. |
ValidateOnly | boolean | List 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.
| Entity | Collection Name | Single | Key | Access |
|---|---|---|---|---|
MGCLatticeRecurringJobHealthEntity | LatticeRecurringJobHealths | LatticeRecurringJobHealth | JobName | Read; write the thresholds and alert switch; actions Refresh, RefreshAll |
MGCLatticeRecurringJobMessageEntity | LatticeRecurringJobMessages | LatticeRecurringJobMessage | MessageId | Read-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.
| Member | Writable | Meaning |
|---|---|---|
JobName | On create | The recurring data job (must exist). |
ActivityId, JobDescription, Direction, JobState, DataProjectName | No | From the job. |
WindowHours | Yes | Failure window in hours; 0 = 24. |
BacklogAgeMinutes | Yes | How long the oldest waiting message may wait; 0 = three recurrence intervals, at least 15 minutes. |
SilenceMinutes | Yes | How long an active job may go without a message; 0 = off. |
StuckMinutes | Yes | How long a message may stay in processing; 0 = 60. |
FailureThreshold | Yes | Failed messages that make the job Failing (and partially processed messages that give a warning); 0 = 1. |
AlertsEnabled | Yes | Raise the Recurring data job health changed business event for this job. |
HealthState | No | Inactive, Healthy, Warning, Failing or Broken. |
PreviousHealthState, StateChangedDateTime | No | The state before the last change, and when it changed. |
EvaluatedDateTime, Reasons | No | When the health was evaluated; one reason per line, worst first. |
BacklogCount, OldestBacklogDateTime | No | Messages waiting (import: enqueued; export: not acknowledged) and since when. |
FailedMessageCount, PartialExecutionCount | No | Failed messages, and messages processed with failed rows, in the failure window. |
LastMessageDateTime, StuckMessageCount, EnabledClientCount, MappingErrorCount | No | The 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, MonitoringBatchJobStatus | No | The job's batch jobs (0 = missing). |
Health rules (the worst that applies wins):
| State | When |
|---|---|
Broken | An 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. |
Failing | Failed messages in the window reach the failure threshold. |
Warning | Waiting 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. |
Healthy | An active job no rule flags. |
Inactive | The job is off and nothing waits. |
Actions:
| Action | Bound to | Returns |
|---|---|---|
Refresh | A row | Evaluates that job now and returns its health state (for example "Healthy"). |
RefreshAll | The entity set | Evaluates 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:
- Original succeeded → cached replay. On success the claim is finalized to
Succeededwith the resultingDocumentId. A duplicate replays that cached outcome instead of re-executing. The replay carriesSuccess=true,Status=Succeeded,ErrorCode=None, a freshly generatedExecutionId, replay timestamps forStartDateTimeUtc/EndDateTimeUtc(current UTC, not1900-01-01), aDurationMsof0, the originalDocumentId/PostedDocumentId/CorrelationId, and an informational message noting it is a cached response. - 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=RequestInProgresswithIsRetryable=trueandStatus=Processing- retry once the original completes. - Original failed → retryable. On failure the claim row is deleted (failures are not cached), so resubmitting the same
RequestIdre-executes the operation. Transiently failed requests can therefore be safely retried. - Stale claim → needs review. If a claim was left
Processingfor more than 60 minutes (its owning worker stopped before recording completion), a duplicate is not executed: it receivesErrorCode=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. - Another operation → refused. A
RequestIdbelongs to the operation that first used it. Sending it to a different operation, of the same or another service, is refused withSuccess=false,ErrorCode=DuplicateRequestandIsRetryable=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.
| Category | ErrorCode | HTTP Status | Success | IsRetryable | Description |
|---|---|---|---|---|---|
| Validation error | ValidationFailed | 200 | false | false | Bad input data (incl. empty RequestId). Fix the request and resubmit. |
| Unknown legal entity | ValidationFailed | 200 | false | false | LegalEntityId names no accessible legal entity. |
| Document not found | DocumentNotFound | 200 | false | false | Referenced document does not exist. |
| Invalid status | InvalidStatus | 200 | false | false | Document is in a state that does not allow the operation. |
| Business rule error | BusinessRule | 200 | false | false | The 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 unresolved | DimensionValueNotFound | 200 | false | false | A supplied financial dimension/account value could not be resolved. |
| Runtime/CLR error | TransientRuntime | 200 | false | true | Transient infrastructure error. Retry with backoff. |
| Request in progress | RequestInProgress | 200 | false | true | An identical RequestId is still executing. Retry once it completes. |
| RequestId used by another operation | DuplicateRequest | 200 | false | false | The RequestId belongs to a different operation, of the same or another service. Send a new RequestId. |
| Earlier attempt needs review | RequestNeedsReview | 200 | false | false | An earlier attempt with this RequestId stopped without a result. Check whether it posted before resubmitting. |
| Configuration missing | ConfigurationMissing | 200 | false | false | Setup the operation needs (a number sequence, a chart of accounts) is missing. |
| License not valid | LicenseNotValid | 200 | false | true | The product license is not valid. Retry once it is renewed. |
| Platform throttling | (n/a) | 429 | N/A | true | Server overloaded. Retry after Retry-After header value. |