Scenario: Pay vendors and settle their invoices
Goal. Pay what you owe your vendors and close the invoices you paid. Either D365 proposes the payments for the invoices that are due and you post the proposal, or your bank or treasury system makes the payment and you record it in D365 and settle it against the invoice it pays. Either way the invoice ends settled, with nothing left open.
When to use. The last step of procure-to-pay, after the invoices are posted and approved, for example with Receive and invoice a purchase order or Register vendor invoices and approve them later. Use Part A when D365 decides what to pay (and, for check payments, draws the checks), Part B when the payment was decided and executed outside D365. Pay each invoice through one of the two paths, not both. Part C records an advance paid against a purchase order before it is invoiced, and Part D reverses a payment recorded in error.
Prerequisites
-
Security. The D365 user your Entra application is mapped to needs:
MGCLatticeAccountsPayableServiceMaintainforgeneratePaymentProposalandgenerateVendorPayments(MGCLatticeAccountsPayableServiceGroup);MGCLatticeGeneralLedgerServiceMaintainforpostVendorPaymentJournalandsettleVendorTransactions(MGCLatticeGeneralLedgerServiceGroup);MGCLatticePaymentReverseMaintain("Payments - reverse customer and vendor payments (high-risk)") forreverseVendorPayment. It is in the high-risk dutyMGCLatticeIntegrationServiceHighRiskDutyof the integration administrator role only.
The first two privileges are in duty
MGCLatticeIntegrationServiceOperationsDuty(integration operator and administrator roles). ReadingLatticeVendorTransactionsandLatticeVendorSettlementscomes withMGCLatticeDataEntitiesView, which all three integration roles hold. The standardVendorPaymentJournalLinesentity needs D365's own privileges. -
Open, approved invoices. Invoices posted outright, approved after an invoice register, or posted from a purchase order. An invoice still waiting in the vendor invoice pool is not approved and is not proposed.
-
A vendor payment journal name of type vendor disbursement (
Payment, USMFVendPay) with a voucher number sequence (General ledger > Journal setup > Journal names). -
Method of payment and bank account. USMF
ELECTRONICposts directly.CHECK(payment type Check, export format Check) is a check payment: a line can post only after Generate payments has drawn its check number, which Lattice does withgenerateVendorPayments(Part A) orGeneratePayments(Part B). The check is drawn on the bank account the line pays from, which needs a check layout with checks left (USMFUSMF OPER: free numbering, the next check is the highest check number + 1). Methods of payment that export a payment file (a file format or an Electronic reporting format) are not generated through Lattice: generate those payments in the vendor payment journal. The bank account is a bank account id (USMFUSMF OPER), not a main account. -
For a prepayment (Part C): the prepayment posting profile in the Accounts payable parameters (Posting profile with prepayment journal voucher), and an open purchase order of the vendor. When the parameters calculate sales tax on prepayments, the line takes the vendor's sales tax group and the default item sales tax group, as the payment journal does.
-
For a reversal (Part D): the general ledger number sequences for reversal vouchers and trace numbers, and the Accounts payable closing voucher number sequence. For a check, when the cash and bank management parameters require check reversals to be reviewed (Use review process for payment reversals; USMF does), a journal name of type Check reversal with a voucher number sequence (USMF
CheckRev). -
Lattice. A valid license for the write operations. To send your own vendor keys, set up an external system and send
AccountNumExternalKeywithExternalSystem(see Cross-reference keys).
Steps
Calls are POST https://<your-environment>/api/services/<ServiceGroup>/<ServiceClass>/<operation> with an
OAuth 2.0 client-credentials token and the request in _request. Use a new RequestId per request and the same
one when you retry it.
Part A: pay what is due with a payment proposal
-
Run the proposal with
generatePaymentProposal(MGCLatticeAccountsPayableServiceGroup/MGCLatticeVendorPaymentProposalService). It creates a vendor payment journal and runs the standard vendor payment proposal into it: the open, approved vendor transactions due fromFromDueDatethroughToDueDate(default today), optionally only those withMethodOfPayment, become payment lines.{ "_request": { "RequestId": "47c2e9a0-1b5d-4f83-96e4-0a7d3c18b2f6", "LegalEntityId": "USMF","UserContext": "Admin", "JournalNameId": "VendPay", "FromDueDate": "2026-10-01", "ToDueDate": "2026-10-31" } }DocumentIdandPostedDocumentIdare the journal number, and the message gives the counts: "Vendor payment journal ... was created with 3 payment line(s) for 4 proposed open transaction(s) due through ... The journal is not posted." When nothing is due, the response still succeeds, names no journal (DocumentIdempty) and says that no payment journal was created. The proposal marks each proposed invoice for settlement by its payment line, so an invoice in an open proposal journal is not proposed again. -
Review the lines through the standard entity:
GET https://<your-environment>/data/VendorPaymentJournalLines?$filter=JournalBatchNumber eq '<journal>' and dataAreaId eq 'USMF'&cross-company=true. -
Generate the checks and post the journal. Lattice leaves the proposal journal unposted so that someone can check it. Then post it in D365 (Accounts payable > Payments > Vendor payment journal, select the journal, open its Lines, Generate payments for check lines, and Post), or let your system do it with
generateVendorPayments(same service):{ "_request": { "RequestId": "91c3e5a7-2b4d-4f6a-8c0e-3d5f7b9a1c4e", "LegalEntityId": "USMF","UserContext": "Admin", "JournalNum": "<journal>", "PostAfterGenerate": true } }It generates the payments of the journal as the lines page's Generate payments does for check payments. Each vendor line with payment status None or Rejected whose method of payment needs generation before it can post (USMF
CHECK) gets the next check number of the check layout of the bank account it pays from as its payment reference; its payment status becomes Sent, and the check is recorded in the bank account's checks with status Payment, the vendor, the amount and the payment voucher. Lines that post without generation (USMFELECTRONIC) are left as they are.MethodOfPaymentlimits the run to the lines with that method, andBankAccountIdto the lines that pay from that bank account. WithPostAfterGeneratethe journal is posted in the same transaction: if the posting fails, no check is used either. Without it the journal stays open with its checks drawn.DocumentIdis the journal;PostedDocumentIdthe first payment voucher when the journal was posted, otherwise the first check number. The message lists the checks ("Generated 2 check payment(s) in vendor payment journal ...: check(s) 792, 793. The journal is posted; the first payment voucher is ..."), andInformationalMessageshas one line per check with its vendor, amount, voucher and bank account. The check document is not printed: the standard check report prints only to a network printer or to a file sent to a user's browser, which a service call cannot use. Print check copies in D365 when you need them (the journal's Print > Check copy, or the bank account's checks). A journal whose lines need no generation, or whose checks are already generated, can also be posted withpostLedgerJournal(Post an existing journal).Posting pays the vendors and settles the invoices the proposal marked.
Part B: record a payment made elsewhere and settle it
-
Post the payment with
postVendorPaymentJournal(MGCLatticeGeneralLedgerServiceGroup/MGCLatticePaymentJournalService). It creates a vendor payment journal with your lines and posts it. A vendor payment debits the vendor (AmountCurDebit);BankAccountIdis the bank it was paid from. A vendor payment line takes noInvoiceId: you name the invoice when you settle.{ "_request": { "RequestId": "e8b31d74-0c6a-4925-bf18-6d4a2e90c157", "LegalEntityId": "USMF","UserContext": "Admin", "JournalNameId": "VendPay", "Description": "Bank run 2026-10-07","PostingDate": "2026-10-07","Lines": [ { "AccountNum": "US-101", "AmountCurDebit": 750.00, "CurrencyCode": "USD","BankAccountId": "USMF OPER", "MethodOfPayment": "ELECTRONIC", "Description": "Payment VINV-2026-0388","TransDate": "2026-10-07" } ] } }DocumentIdandPostedDocumentIdare the journal number; success is reported only when the journal posted.A check payment posts in the same call with
"GeneratePayments": trueon the request: each line whose method of payment needs generation ("MethodOfPayment": "CHECK") gets the next check number of itsBankAccountId's check layout before the journal posts, in one transaction, and the message lists the check numbers (Vendor payment journal ... posted successfully with check(s) 794.). Such a line must sendBankAccountId. WithoutGeneratePayments(the default) D365 refuses a check line at posting with "Check number must be filled in" (BusinessRule), and the journal is deleted. -
Find the payment's voucher. A vendor payment is settled by its voucher. Read the vendor's payment transactions of the day:
GET https://<your-environment>/data/LatticeVendorTransactions?$filter=VendorAccountNumber eq 'US-101' and TransactionType eq Microsoft.Dynamics.DataEntities.LedgerTransType'Payment' and TransactionDate eq 2026-10-07 and dataAreaId eq 'USMF'&$select=Voucher,TransactionCurrencyAmount,SysRecId&cross-company=true. Your payment is the row with its amount; the newest one has the highestSysRecId. -
Settle it against the invoice with
settleVendorTransactions(MGCLatticeGeneralLedgerServiceGroup/MGCLatticePaymentJournalService). Name the payment byPaymentVoucher(orPaymentTransRecId, the transaction'sSysRecId) and each invoice byInvoiceId(orInvoiceTransRecId).SettleAmountCuris the amount to settle on that invoice; 0 or omitted settles its whole open balance, and no more than the open balance is ever settled.{ "_request": { "RequestId": "5a0f7c3e-d218-4b96-a4e0-8c1b6f29d375", "LegalEntityId": "USMF","UserContext": "Admin", "AccountNum": "US-101", "PaymentVoucher": "VPAY-000123","Lines": [ { "InvoiceId": "VINV-2026-0388", "SettleAmountCur": 750.00 } ] } }DocumentIdis the payment's voucher; a settlement creates no document, soPostedDocumentIdis empty. -
Read the settlement back from
LatticeVendorSettlements($filter=VendorAccountNumber eq 'US-101' and dataAreaId eq 'USMF'&cross-company=true). Each side of a settlement has its own row:TransRecIdis the settled transaction andOffsetRecIdthe one it was settled against, so the pair of the invoice's and the payment'sSysRecId(in either order) is your settlement, withSettledTransactionCurrencyAmountandSettlementVoucher. The invoice'sSysRecIdis on itsLatticeVendorTransactionsrow (InvoiceId eq 'VINV-2026-0388', the row that is not a payment).
Part C: pay an advance against a purchase order
-
Post the payment as a prepayment with
postVendorPaymentJournal, as in step 4, with the line markedIsPrepaymentand the order inPurchaseOrderId(orPurchaseOrderIdExternalKeywithExternalSystem):{ "_request": { "RequestId": "b3d5f7a9-1c2e-4f60-8a4c-6e8f0a2c4e71", "LegalEntityId": "USMF","UserContext": "Admin", "JournalNameId": "VendPay", "Description": "Advance PO 00001042","PostingDate": "2026-10-07","Lines": [ { "AccountNum": "US-101", "IsPrepayment": true, "PurchaseOrderId": "00001042","AmountCurDebit": 100.00, "CurrencyCode": "USD", "BankAccountId": "USMF OPER","MethodOfPayment": "ELECTRONIC", "Description": "Advance for 00001042", "TransDate": "2026-10-07" } ] } }The prepayment posts with the prepayment posting profile of the Accounts payable parameters (without one, D365 uses the default posting profile and
Warningssays so). The order is checked before the journal is created: it must exist, be invoiced by the line's vendor, and be neither invoiced nor canceled. After posting, the payment is marked against the order as the order's settlement does, andInformationalMessagesnames the order. When the order is invoiced (Receive and invoice a purchase order), its invoice settles the prepayment. When the vendor sends a prepayment invoice for the order instead, post it with Post a vendor prepayment invoice for a purchase order and pay it like any invoice.
Part D: reverse a payment
-
Reverse the payment with
reverseVendorPayment(MGCLatticeGeneralLedgerServiceGroup/MGCLatticePaymentJournalService). It reverses a posted payment voucher of the vendor with the standard reversal that covers it:The payment was Reversed by Made by check (a check of the payment's bank account) The check reversal (Payment reversal on the Checks page). When the cash and bank management parameters require check reversals to be reviewed in a check reversal journal (USMF does), it creates that journal with the canceling line and the check becomes Pending cancellation; the journal is left for review, or posted in the same request with PostReversalJournal.Not posted to a bank account The vendor transaction reversal. A settled payment is refused: unsettle it first. Posted to a bank account, not by check (as in step 4) Nothing: D365 has no standard reversal for it, so the operation refuses it with BusinessRule. Correct it in D365.{ "_request": { "RequestId": "d7f9b1c3-5e6a-4b8d-9f2a-4c6e8a0b2d93", "LegalEntityId": "USMF","UserContext": "Admin", "AccountNum": "US-101", "Voucher": "VPAY-000123","ReversalDate": "2026-10-08", "ReasonCode": "ERROR", "ReasonComment": "Duplicate payment" } }ReversalDatedefaults to today and cannot be before the payment date.ReasonCodeis required when the parameters demand one (cash and bank management Require reasons for payment reversals for a check).DocumentIdis the reversed payment voucher andPostedDocumentIdthe reversal voucher.For a check under the review setting,
ReversalJournalNameIdnames the check reversal journal name (USMFCheckRev; without it, the legal entity's only one), and"PostReversalJournal": trueposts that journal in the same request, which reverses the payment and its settlements and cancels the check (PostedDocumentIdis then the reversal voucher). Without it the journal is left for review on Cash and bank management > Payment reversal approvals > Check reversals, the check is Pending cancellation, andPostedDocumentIdis the check reversal journal; posting that journal in D365 completes the reversal.
How to verify
- Proposal:
Successtrue and a journal number;VendorPaymentJournalLinesfor that journal has as many lines as the message reports. After you post it, the proposed invoices are settled. - Checks: every check line of the journal has its
CheckNumber(andPaymentReference) inVendorPaymentJournalLines; in D365, the journal lines show payment status Sent, and Cash and bank management > Bank accounts, selectUSMF OPER, then Checks, lists each check with status Payment, the vendor and the voucher. After posting,LatticeVendorTransactionsandLatticeBankAccountTransactionshave the payment voucher. The Vendor check issued business event fires for each check, if you have activated it. - Payment:
Successtrue,Status3, the journal number inDocumentId, and aPaymenttransaction inLatticeVendorTransactions. Resending the same request returns "Duplicate request detected" with the same journal number and posts nothing. - Settlement:
DocumentIdis the payment voucher,LatticeVendorSettlementshas the invoice/payment pair, and the invoice'sRemainingTransactionCurrencyAmountinLatticeVendorTransactionsis 0 with aClosedDateonce fully settled. - In D365: Accounts payable > Vendors > All vendors, select
US-101, then Transactions. - Prepayment:
Successtrue andInformationalMessagesnaming the order; once the order is invoiced, the prepayment'sSettledTransactionCurrencyAmountinLatticeVendorTransactionsis no longer 0. - Reversal:
Successtrue,DocumentIdthe payment voucher, andLatticeVendorTransactionshas a transaction on the returnedPostedDocumentIdwith the opposite amount. A check reversal left for review returns the check reversal journal instead: the check is Pending cancellation on the bank account's Checks until the journal is posted, then Canceled. - The Vendor payment journal posted business event fires after a vendor payment journal posts (from the API or from the journal page), once per vendor posting, if you have activated it.
When it goes wrong
ErrorCode arrives as an integer (1 ValidationFailed, 2 DocumentNotFound, 3 InvalidStatus, 4 BusinessRule,
11 ConfigurationMissing).
- Proposal finds nothing (
Successtrue, noDocumentId): no open, approved invoice is due in the window with that method of payment. Check that the invoices are approved (not still in the invoice pool) and not already in another unposted proposal journal. - Proposal,
ValidationFailed:JournalNameIdmissing, unknown or not a vendor payment journal name, orFromDueDatelater thanToDueDate.DocumentNotFound: unknownMethodOfPayment. A failure after the journal was created deletes the empty journal again. ConfigurationMissing(proposal or payment): the journal name has no voucher number sequence.- Generate payments,
ValidationFailed: noJournalNum; 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 ("Only check payments can be generated through the service; generate payment files in the vendor payment journal."); a journal without lines or without a line to generate.DocumentNotFound: an unknown journal.InvalidStatus: the journal is posted, blocked by the system or in use by another user, needs workflow approval and is not approved, or "The payments of journal ... are already generated".ConfigurationMissing: the method of payment has no export format, the bank account has no check layout, or a fixed check numbering has no created checks left.BusinessRule: the standard generation skipped a line (its messages are inErrors) or the posting failed; nothing is generated then either. - Payment,
ValidationFailed: journal name missing, unknown or of the wrong type; no lines or an empty line;AccountNumis not a vendor;BankAccountIdis not a bank account; a line carriesInvoiceId(identify the payment by its voucher when you settle it); withGeneratePayments, a check line withoutBankAccountId, a line whose method of payment exports a payment file, orGeneratePaymentson a customer payment journal.ConfigurationMissingwithGeneratePayments: as for Generate payments above. Nothing was created. - Payment,
BusinessRule: D365 refused to post the journal, for example a check line sent withoutGeneratePayments("Check number must be filled in"). The messages are inErrors. The service deletes the journal it created, so fix the cause and send the payment again. - Settle,
ValidationFailed:AccountNummissing or not a vendor, noPaymentVoucher/PaymentInvoiceId/PaymentTransRecId, no lines, or a line withoutInvoiceIdorInvoiceTransRecId. - Settle,
DocumentNotFound: no payment transaction of this vendor with that voucher or RecId, or no invoice transaction of this vendor with that number or RecId. A RecId of another vendor's transaction, or of a payment used as an invoice, is refused the same way. - Settle,
BusinessRule: the payment or the invoice has no open balance left ("has no open balance to settle"), or nothing was settled. A payment posted as a credit to the vendor is a refund, not a payment, and cannot be settled against an invoice. - Prepayment,
ValidationFailed: a sales order on a vendor line ("SalesOrderId applies to customer payments only."), an unknown purchase order, or an order of another vendor.InvalidStatus: the order is invoiced or canceled. Nothing was created. - Reversal,
ValidationFailed: noAccountNumorVoucher, an unknown vendor or reason code, a reversal date before the payment date, a reason the parameters require, aReversalJournalNameIdthat is unknown or not a check reversal journal name, or several check reversal journal names and none requested.DocumentNotFound: "Vendor payment voucher ... was not found on account US-101."InvalidStatus: the payment is already reversed, or its check is already reversed, pending reversal (a check reversal journal exists for it) or not in status Payment.BusinessRule: "Vendor payment ... was posted to bank account ... and was not made by check. A vendor payment posted to a bank account can only be reversed by a check reversal."; a settled payment not posted to a bank account ("Unsettle it before you reverse it.").ConfigurationMissing: a reversal number sequence is not set up; the parameters require a check reversal journal but no check reversal journal name exists, or it has no voucher number sequence. A refused reversal reverses nothing. - Preview and retries:
PreviewMode: trueis refused withPreviewUnsupported. Resending a request with the sameRequestIdreturns the recorded result: a payment journal is never posted twice, a settlement never applied twice and a payment never reversed twice. A request that stopped between creating and posting its payment journal is resolved by the idempotency reconciliation sweep (see Idempotency reconcile runbook).
Reference
- API reference: sections 9 (Payment Journal Service) and 15 (Vendor Payment Proposal Service)
- Endpoint payload specification: request payloads per operation
- Security model: privileges, duties and roles (the reversal is in
MGCLatticeIntegrationServiceHighRiskDuty) - Cross-reference keys: sending your own vendor keys
- Idempotency reconcile runbook: resolving a stranded request
- Vendor payment journal posted event, Vendor check issued event
- Related: Post an existing journal, Register vendor invoices and approve them later, Receive and invoice a purchase order, Post a vendor prepayment invoice for a purchase order, Post a pending vendor invoice