Scenario: Post a journal that already exists in D365
Goal. A journal is prepared somewhere other than your integration: a person enters it on its journal page, a data management import creates it, or another system builds it through the standard journal entities. Your system decides when it posts. Lattice posts the journal the way Post on its journal page does, with the standard posting of the journal type, completely or not at all, and tells you what it posted.
When to use. Journals reviewed or approved in D365 before they post, journals created in bulk by set-based imports or by the standard entities, and a scheduler that posts what is ready at the end of the day. When your system has the lines and wants one journal created and posted in one call, use the posting operation of the journal type instead (General and intercompany journals, Inventory journals, Project journals and invoicing, Production order lifecycle and the others).
| Operation | Journals | Request member |
|---|---|---|
postLedgerJournal | General journal, customer payment journal, vendor payment journal, invoice register, vendor invoice journal, invoice approval journal, project expense journal, fixed asset journal | JournalNum (or JournalNumExternalKey with ExternalSystem) |
postInventoryJournal | Movement, profit/loss (adjustment), counting, transfer, BOM, tag counting, ownership change, project item and fixed asset inventory journals | JournalId |
postProjectJournal | Project hour and fee journals | JournalId |
postProductionJournal | Picking list, route card, job card and report as finished journals | JournalId |
postTradeAgreementJournal | Trade agreement journals (sales and purchase prices and discounts) | JournalNum |
Prerequisites
-
Security.
MGCLatticeJournalPostingMaintain("Journal posting - post existing journals") grants the five operations and their batch variants. It is in dutyMGCLatticeIntegrationServiceOperationsDuty(integration operator and administrator roles). The privilege alone posts nothing: the caller must also hold every Lattice operation that would post the journal's content, so posting an existing journal never lets a caller do more than the operations it holds would. When one is missing, the request is refused withAccessDeniedand the message names all the missing operations.Journal type Operation the caller must also hold General journal MGCLatticeGeneralLedgerJournalService.postGeneralJournalCustomer payment journal MGCLatticePaymentJournalService.postCustomerPaymentJournalVendor payment journal MGCLatticePaymentJournalService.postVendorPaymentJournalInvoice register, vendor invoice journal MGCLatticeVendorInvoiceJournalService.postInvoiceRegisterJournalInvoice approval journal MGCLatticeVendorInvoiceJournalService.postInvoiceApprovalJournalProject expense journal MGCLatticeProjectJournalService.postExpenseJournalFixed asset journal Decided by its lines (below) Inventory movement, profit/loss, counting, transfer, BOM, tag counting, ownership change journal MGCLatticeInventoryJournalPostingService.postMovementJournal,postAdjustmentJournal,postCountingJournal,postTransferJournal,postBOMJournal,postTagCountingJournal,postOwnershipChangeJournalProject item journal (inventory) MGCLatticeProjectJournalService.postItemJournalFixed asset inventory journal MGCLatticeFixedAssetService.postAcquisitionProject hour journal, fee journal MGCLatticeProjectJournalService.postHourJournal,postFeeJournalPicking list; route card and job card; report as finished journal MGCLatticeProductionOrderPostingService.postPickList,postRouteCard,reportAsFinishedTrade agreement journal MGCLatticeSalesTradeAgreementService.setSalesPriceIn a ledger journal of any type, these lines need one more operation each:
Line Operation the caller must also hold An intercompany line: its account company or offset company is another legal entity MGCLatticeGeneralLedgerJournalService.postIntercompanyJournalA fixed asset line (every line of a fixed asset journal, and in any other journal a line whose account or offset type is Fixed assets) with transaction type Acquisition MGCLatticeFixedAssetService.postAcquisitionA fixed asset line with transaction type Disposal - sale or Disposal - scrap MGCLatticeFixedAssetService.postDisposalA fixed asset line with any other transaction type (acquisition adjustment, depreciation, revaluation, write-up or write-down adjustment...) MGCLatticeFixedAssetService.postAssetTransactionA project line (account or offset type Project) MGCLatticeProjectJournalService.postExpenseJournalCustomer, vendor and bank lines of a general journal are covered by
postGeneralJournal. For example, a general journal with an intercompany line and a fixed asset disposal line needspostGeneralJournal,postIntercompanyJournalandpostDisposal; the last two are high-risk operations of the integration administrator role. Creating the journal through the standard entities needs D365's own privileges for them. See Security model. -
D365 configuration. The journal name of the journal, with its number sequences (USMF
GenJrnfor general journals,IMovfor inventory movements,Hourfor project hours,Pickfor picking lists,S_Pricefor sales price agreements), and whatever the standard posting of the journal type needs: accounts, open periods, on-hand inventory, a started production order, and so on. A journal under an approval workflow, or whose journal name requires approval, must be approved first. -
Lattice. A valid license (an expired or invalid one refuses the call with
LicenseNotValid). To name a ledger journal by your own key, register it as a cross-reference and sendJournalNumExternalKeywithExternalSystem(Use your own keys).
Steps
The operations are on MGCLatticeJournalPostingService in service group MGCLatticeJournalPostingServiceGroup.
Send a POST with an OAuth 2.0 bearer token and the request in _request (see Trial and day-one guide).
-
Create the journal. Skip this step when the journal was entered in D365 or imported. Otherwise create it through its standard entities; for a general journal, the header:
POST https://<your-environment>/data/LedgerJournalHeaders{ "dataAreaId": "usmf", "JournalName": "GenJrn", "Description": "October accruals" }The answer carries the new journal's
JournalBatchNumber. Then the lines; the voucher comes from the journal name:POST https://<your-environment>/data/LedgerJournalLines{"dataAreaId": "usmf","JournalBatchNumber": "<JournalBatchNumber>","LineNumber": 1,"TransDate": "2026-10-23T12:00:00Z","AccountType": "Ledger","AccountDisplayValue": "110110","OffsetAccountType": "Ledger","OffsetAccountDisplayValue": "110180","DebitAmount": 1000.00,"CurrencyCode": "USD","Text": "Accrual"} -
Post it when it is complete. Name the journal by its number:
POST https://<your-environment>/api/services/MGCLatticeJournalPostingServiceGroup/MGCLatticeJournalPostingService/postLedgerJournal{"_request": {"RequestId": "c2a4e6f8-1b3d-4f5a-9c7e-0d2f4a6c8e1b","LegalEntityId": "USMF","UserContext": "close-scheduler","JournalNum": "<JournalBatchNumber>"}}A ledger journal posts as the page's Post posts it, not Post and transfer: one voucher that fails cancels the whole posting and the journal stays as it was. Lattice checks the journal before it posts: its type, your rights for it (Prerequisites, step 1), that it is not posted, locked or in use, that its approval is complete, and that it has lines.
-
Read the result.
DocumentIdis the journal. For a ledger journal,PostedDocumentIdis its first voucher in voucher order and the message counts the vouchers and lists the first 25:Ledger journal 000912 (Daily) was posted with 1 vouchers: GNJL001240.Warnings and information from the posting are inWarningsandInformationalMessages. -
The other journal families take the same request with
JournalId(JournalNumfor trade agreements), and answer with the journal in bothDocumentIdandPostedDocumentId:Journal Operation Create it with Posted in D365 Inventory journals postInventoryJournalThe journal page, the set-based Inventory journal lines (set-based), or InventoryMovementJournalHeaders+InventoryMovementJournalEntriesV2Inventory management > Journal entries; the item transactions Project hour and fee journals postProjectJournalThe journal page, Project journal lines (set-based), or JournalTables+JournalTransProject management and accounting > Journals; the posted project transactions Production journals postProductionJournalThe production order's journals, the set-based production entities, or ProductionPickingListJournalEntriesThe production order's Production journals; the consumption and the finished goods Trade agreement journals postTradeAgreementJournalThe journal page, Trade agreement journal lines (set-based), or TradeAgreementJournalHeaders+OpenSalesPriceJournalLinesSales and marketing > Prices and discounts > Trade agreement journals; the agreement on the item - A tag counting journal posts as the standard posts it: it creates a counting journal with the counted quantities and leaves it open for review; the message names that counting journal.
- A report as finished journal first creates the quality orders that quality associations require before a report as finished, as the page does; they stay when the posting is then refused.
- A trade agreement journal validates every line before it posts. When the accounts receivable parameter Check for overlaps and gaps is on, a journal whose quantity or amount ranges overlap or leave gaps is not posted. Trade agreements marked for deletion (the journal page's Delete trade agreements) are deleted by the posting, as on the page.
The bulk variants (postLedgerJournalBatch, postInventoryJournalBatch, postProjectJournalBatch,
postProductionJournalBatch, postTradeAgreementJournalBatch) take { "_requests": [ ... ] }, each item a full
request with its own RequestId, and answer one result per item. All five operations can also be queued with
submitAsyncOperation, which is the way to post a large journal: the standard posts a ledger journal above the
ledger journal line limit only in batch. See Batch and async operations. None of
the operations has a preview.
How to verify
- The response:
Successtrue,Status3,DocumentIdthe journal,PostedDocumentIdthe first voucher (ledger) or the journal (every other family). - A ledger journal:
LedgerJournalHeaderswith$filter=JournalBatchNumber eq '<journal>' and dataAreaId eq 'usmf'&cross-company=trueshowsIsPostedYes;LatticeGeneralLedgerEntrieswith$filter=JournalNumber eq '<journal>' and LegalEntityId eq 'USMF'shows the posted account entries, the returned voucher inSubledgerVoucher. - The other families: the header entity shows the journal posted (
InventoryMovementJournalHeaders,JournalTables,LatticeProductionJournalHeadersIsPosted,TradeAgreementJournalHeaders), and the transactions exist: item transactions,LatticeProjectPostedTransactionsfor the journal's lines, the production order's consumption, the agreement inSalesPriceAgreements. - In D365: the journal page of the type, with its filter set to show posted journals.
- The call: System administration > Inquiries > Lattice > Services > Service call log, or
LatticeServiceCallLogsfiltered on yourRequestId. - A general journal fires the General journal posted business event, as when it is posted from its page.
When it goes wrong
A failed call answers Success false, Status 4, an ErrorCode and the message "The journal was not posted:
the request was refused or the standard posting failed."; the reasons are in Errors. The journal stays as it was.
| ErrorCode | Typical cause (text in Errors) | What to do |
|---|---|---|
ValidationFailed (1) | No RequestId or unknown LegalEntityId; no JournalNum / JournalId, or a journal key that does not resolve; "Journal ... is a Periodic journal, which postLedgerJournal does not post. It posts these journal types: ..." (allocation, elimination, periodic, budget, project beginning balance and other types no Lattice operation posts); "Journal ... has no lines to post." | Correct the request. Post other journal types in D365. |
DocumentNotFound (2) | "Ledger journal ... was not found in legal entity ..." (the same for inventory, project, production and trade agreement journals) | Check the number, and that the request's LegalEntityId is the journal's. |
AccessDenied (14) | "You do not have access to MGCLatticeGeneralLedgerJournalService.postIntercompanyJournal, which posting journal ... requires, so the journal was not posted." | Grant the caller the operations named (Prerequisites, step 1), or post the journal in D365. |
InvalidStatus (3) | "Journal ... is already posted."; locked by the system while another process validates or posts it; private to another user; locked by a user group the caller is not in; in use by another user; "it uses workflow approval, and its approval status is ..., not Approved."; "journal name ... requires approval, and the journal has not been approved."; a project journal under journal approval that is not ready for posting (this applies to every caller, including system administrators) | Close, release or approve the journal in D365, then resend. A posted journal needs nothing more. |
BusinessRule (4) | D365 refused the posting: an unbalanced voucher, accounts, dimensions, a closed period, on-hand inventory, an item on hold, the production order's status, overlapping or missing trade agreement ranges; its messages are in Errors and Warnings. Also a ledger journal above the ledger journal line limit posted outside batch | Fix the journal in D365, then resend. Queue a very large ledger journal with submitAsyncOperation. |
PreviewUnsupported (10) | PreviewMode true | Send without PreviewMode. Nothing was run. |
TransientRuntime (6) | A runtime fault; IsRetryable true | Resend with the same RequestId. |
LicenseNotValid (12) | The Lattice license is expired or invalid | Renew the license, then resend. |
Retries are safe. Resending a successful request with the same RequestId posts nothing again: the answer
repeats the original result with the message Duplicate request detected. Original request processed at .... A
new RequestId for a journal that is already posted is refused with InvalidStatus. See
Post a journal exactly-once.
Reference
- API reference: Journal Posting Service, and section 19 (Bulk Operations)
- Endpoint payload specification:
MGCLatticeJournalPostingService - Security model:
MGCLatticeJournalPostingMaintain - Cross-reference keys:
JournalNumExternalKey - Import journals in bulk, Batch and async operations, Post a journal exactly-once