Scenario: Register vendor invoices and approve them later
Goal. Record a vendor invoice the day it arrives, before anyone has decided which expense account it belongs to, and approve it to that account later. The invoice register journal books the liability to the vendor against a pending-invoice account and parks the invoice, unapproved, in the vendor invoice pool. The invoice approval journal takes it out of the pool, moves the amount to the expense account and approves it. Only an approved invoice is picked up for payment.
When to use. Invoices without a purchase order that go through a two-step register-then-approve process, for example when an invoice-capture system registers everything on receipt and a cost-center owner codes it later. If no approval step is needed, post the invoice outright instead (step 1 with a vendor invoice journal name, see the note there). Invoices for purchase orders are posted with Receive and invoice a purchase order.
Prerequisites
- Security. The D365 user your Entra application is mapped to needs
MGCLatticeAccountsPayableServiceMaintainforpostInvoiceRegisterJournalandpostInvoiceApprovalJournal(dutyMGCLatticeIntegrationServiceOperationsDuty, in the integration operator and administrator roles). ReadingLatticeVendorTransactionscomes withMGCLatticeDataEntitiesView, which all three integration roles hold. - Journal names, each with a voucher number sequence (General ledger > Journal setup >
Journal names): an invoice register name (USMF
APInvReg) and an invoice approval name (USMFAPInvApp). - A pending-invoice account. The invoice register posts to the purchasing offset account of the posting profile on the Accounts payable parameters, for the vendor (Accounts payable > Setup > Vendor posting profiles).
- An approver. Every register line needs an "Approved by" worker:
ApproverPersonnelNumber(USMF000020), or else the worker linked to the calling user. - An expense account that allows manual entry for the approval (USMF
601500). The Accounts payable control account (200110) is refused. - Lattice. A valid license for the posting operations. To send your own vendor keys, set up an external
system and send line
VendAccountExternalKeywithExternalSystem(see Cross-reference keys).
Steps
Both operations belong to MGCLatticeVendorInvoiceJournalService in MGCLatticeAccountsPayableServiceGroup:
POST https://<your-environment>/api/services/MGCLatticeAccountsPayableServiceGroup/MGCLatticeVendorInvoiceJournalService/<operation>,
OAuth 2.0 client-credentials token, request in _request. Each call creates a journal and posts it; DocumentId
and PostedDocumentId are that journal's number.
-
Register the invoice with
postInvoiceRegisterJournaland the invoice register journal name. LeaveOffsetMainAccountIdout: the line then gets the pending-invoice account, as it does in the journal page. An invoice is a credit to the vendor.{ "_request": { "RequestId": "3b8e1f60-9d24-4c7a-a5e3-1f0c6d92b748", "LegalEntityId": "USMF","UserContext": "Admin", "JournalNameId": "APInvReg", "Description": "Invoices received 2026-10-07","PostingDate": "2026-10-07","Lines": [ { "VendAccount": "US-101", "InvoiceId": "VINV-2026-0412", "AmountCurCredit": 1000.00,"CurrencyCode": "USD", "InvoiceDate": "2026-10-07", "ApproverPersonnelNumber": "000020" } ] } }Posting credits the vendor, debits the pending-invoice account, and parks the invoice in the vendor invoice pool. The message says so: "... its invoices are in the vendor invoice pool, awaiting postInvoiceApprovalJournal." Each line also takes the vendor's defaults (terms of payment and the due date they give, method of payment, cash discount, bank account, and the vendor's currency when
CurrencyCodeis empty).To post an invoice outright, with no approval step, send the same request with a vendor invoice journal name (USMF
APInvoice) and the expense account inOffsetMainAccountId. The invoice is posted approved and is immediately open for payment; there is nothing to approve. -
The invoice waits in the pool. It is a posted, open vendor transaction, but unapproved: payment proposals do not pick it up. In D365 an approver sees it with Find vouchers in an invoice approval journal.
-
Approve it with
postInvoiceApprovalJournaland the approval journal name. Each line names a registered invoice (VendAccount+InvoiceId) and the expense account to approve it to (OffsetMainAccountId, required). The amount is optional; when you send it, it must equal the registered amount.ApproverPersonnelNumberoverrides the approver from the register.{ "_request": { "RequestId": "d61a0c93-4e7f-4b25-8c1d-a0f5e2b39c67", "LegalEntityId": "USMF","UserContext": "Admin", "JournalNameId": "APInvApp", "Description": "Approval of 2026-10-07 invoices","Lines": [ { "VendAccount": "US-101", "InvoiceId": "VINV-2026-0412", "AmountCurCredit": 1000.00,"CurrencyCode": "USD", "OffsetMainAccountId": "601500" } ] } }The service does what Find vouchers and posting do in the approval journal page: it fetches the invoice from the pool into a new approval journal, adds the expense line for the registered amount, posts, and checks that every invoice is now approved. Posting reverses the pending-invoice entry and books the amount to the expense account. The approval posts on the register's date (or the first open date when that period is closed). The message ends with the number of registered invoices approved.
-
Pay it. The approved invoice is open for payment proposals and payments: Pay vendors.
How to verify
- Both calls:
Successtrue,Status3,DocumentId=PostedDocumentId= the journal number. The register message mentions the vendor invoice pool; the approval message the count of approved invoices. - The invoice is a vendor transaction:
GET https://<your-environment>/data/LatticeVendorTransactions?$filter=VendorAccountNumber eq 'US-101' and InvoiceId eq 'VINV-2026-0412' and dataAreaId eq 'USMF'&cross-company=truereturns it with itsVoucher,DueDateandRemainingTransactionCurrencyAmount. - Approval took it out of the pool: approving the same invoice again is refused with
InvalidStatus, "is already approved (approval journal ...)". - A payment proposal whose due-date window includes the invoice proposes it after the approval, not before.
- In D365: Accounts payable > Vendors > All vendors, select
US-101, then Transactions. - Every call is listed on System administration > Inquiries > Lattice > Services > Service call log.
When it goes wrong
ErrorCode arrives as an integer (1 ValidationFailed, 2 DocumentNotFound, 3 InvalidStatus, 4 BusinessRule,
5 DimensionValueNotFound, 11 ConfigurationMissing).
ValidationFailed, journal name:JournalNameIdis missing, unknown, or of the wrong type. The register takes an invoice register or a vendor invoice journal name; the approval only an approval name.ValidationFailed, lines: no lines, an empty line, or a register line whoseVendAccountis not a vendor. On the approval: a line withoutVendAccount,InvoiceIdorOffsetMainAccountId, or an amount that differs from the registered one ("was registered for ..., but the request line approves ...").ConfigurationMissing: the journal name has no voucher number sequence; no approver could be resolved (sendApproverPersonnelNumberor link the calling user to a worker); the approver's personnel number does not exist; or the vendor has no purchasing offset account in the posting profile.DimensionValueNotFound:OffsetMainAccountIdis not an account of the legal entity's chart of accounts.DocumentNotFoundon the approval: the vendor has no invoice with that number, or nothing was ever registered in the legal entity, so it has no vendor invoice pool.InvalidStatuson the approval: the invoice was posted outright and never registered ("nothing to approve"), is already approved, or is held by another approval journal that was not posted. Post or delete that journal first.BusinessRule: D365 refused the posting, for example an invoice number already used for the vendor or a closed period; the D365 messages are inErrors. When an approval journal fails to post, the service hands its invoices back to the pool, so you can send the approval again. When a register journal fails to post, the service deletes the unposted journal, so fix the cause and send the register again; the invoice is not entered twice.- Not supported by the approval: splitting one invoice over several expense accounts, a posting date other than the register's, and sales tax recalculation. Use the approval journal page for those.
- Preview and retries:
PreviewMode: trueis refused withPreviewUnsupported. Resending a request with the sameRequestIdreturns the recorded journal and never posts twice. If a request stopped between creating and posting its journal, the claim names that journal and the idempotency reconciliation sweep resolves it (see Idempotency reconcile runbook); until then a resend answersRequestInProgressor, after an hour,RequestNeedsReview.
Reference
- API reference: section 16 (Vendor Invoice Journal Service)
- Endpoint payload specification: request payloads per operation
- Security model: privileges, duties and roles
- Cross-reference keys: sending your own vendor keys
- Idempotency reconcile runbook: resolving a stranded request
- Related: Pay vendors, Receive and invoice a purchase order