Skip to main content

Scenario: Return goods to a vendor and post the credit note

Goal. Send goods back to a vendor and get the money back in Accounts payable: create a purchase return order with the vendor's return authorization (RMA) number, confirm it, post the return shipment when the goods leave your warehouse, and post the vendor's credit note. Your system makes the calls; D365 moves the stock out and credits the vendor.

When to use. Defective, wrong or surplus goods that the vendor has agreed to take back, when the return is recorded in an external system (a quality or warehouse system). For the forward flow, see Receive and invoice a purchase order.

Prerequisites​

  1. Security. The D365 user your Entra application is mapped to needs MGCLatticeAccountsPayableServiceMaintain (duty MGCLatticeIntegrationServiceOperationsDuty) for createPurchaseReturn, shipPurchaseReturn, creditPurchaseReturn and confirmPurchaseOrder, and MGCLatticeAccountsPayableServiceView (duty MGCLatticeIntegrationServiceQueryDuty) for getPurchaseOrderStatus. The integration operator and administrator roles hold both.
  2. The vendor's RMA number. D365 does not save a return order without one; the field holds 10 characters.
  3. Stock to ship. The return ships out of the warehouse on its line, so that warehouse must hold the quantity (USMF: item D0001 at site 1, warehouse 11). When purchase order change management is on, the return order must be approved before it can be confirmed.
  4. D365 configuration. The vendor (USMF US-101) with a posting profile and a purchase order number sequence. A return reason code is optional; when you send one it must exist.
  5. Lattice. A valid license for the write operations. To send your own keys, set up an external system and send VendAccountExternalKey, line ItemIdExternalKey or PurchaseOrderIdExternalKey with ExternalSystem (see Cross-reference keys).

Steps​

Calls are POST https://<your-environment>/api/services/MGCLatticeAccountsPayableServiceGroup/<ServiceClass>/<operation> with an OAuth 2.0 client-credentials token and the request in _request. Use a new RequestId per step and the same one when you retry it. DocumentId is always the return order number.

  1. Create the return order with createPurchaseReturn (MGCLatticePurchaseReturnService). The standard purchase order entity covers ordinary orders only, so this operation is how you create a return order through the API. Every line needs ItemId and a non-zero Qty; D365 stores return quantities negative. Name the warehouse the goods leave from with SiteId and WarehouseId (or an InventDimId).

    { "_request": { "RequestId": "8e2c4a17-5b9d-4f06-a3e1-c7d0b6f29a58", "LegalEntityId": "USMF",
    "UserContext": "Admin", "VendAccount": "US-101", "ReturnItemNum": "RMA7788",
    "Lines": [ { "ItemId": "D0001", "Qty": 1, "SiteId": "1", "WarehouseId": "11" } ] } }

    DocumentId and PostedDocumentId are the new return order number, for example 00001063. Add ReturnReasonCodeId to set a return reason on the order.

  2. Confirm it with confirmPurchaseOrder (MGCLatticePurchaseOrderPostingService). A return shipment needs a confirmed order. Send the whole order, without Lines:

    { "_request": { "RequestId": "1f6d3b80-a24e-4c97-8b5a-0e3d9c71f6a2", "LegalEntityId": "USMF",
    "UserContext": "Admin", "PurchaseOrderId": "00001063", "PostingDate": "2026-10-07" } }
  3. Post the return shipment with shipPurchaseReturn (MGCLatticePurchaseReturnService) when the goods leave. PackingSlipId, the return shipment number, is required. The shipment covers the whole return order.

    { "_request": { "RequestId": "c4a90e2b-6d17-4b38-95f0-2e8b1a7c3d64", "LegalEntityId": "USMF",
    "UserContext": "Admin", "PurchaseOrderId": "00001063", "PackingSlipId": "RS-00001063",
    "PostingDate": "2026-10-07" } }

    PostedDocumentId is the return shipment number.

  4. Post the credit note with creditPurchaseReturn (MGCLatticePurchaseReturnService) when the vendor's credit note arrives. InvoiceId, the vendor's credit note number, is required. Once the return has shipped, the credit note is built from the shipped quantity.

    { "_request": { "RequestId": "7b05e3d9-1c42-4a6f-b8e7-94d2f0a51c36", "LegalEntityId": "USMF",
    "UserContext": "Admin", "PurchaseOrderId": "00001063", "InvoiceId": "RC-00001063",
    "PostingDate": "2026-10-07" } }

    PostedDocumentId is the credit note number. The credit is an open vendor transaction that offsets what you owe US-101.

How to verify​

  • Each step: Success true, Status 3, DocumentId = the return order, PostedDocumentId = the created order, the shipment number or the credit note number.
  • getPurchaseOrderStatus (MGCLatticePurchaseOrderPostingService, DocumentId = the return order) works for return orders too: StatusDetails gains ConfirmDate, then ReceiptDate after the shipment and InvoiceDate after the credit note. The standard PurchaseOrderHeadersV2 entity does not list return orders, so use this query, not the entity, to read a return back.
  • In D365: Procurement and sourcing > Purchase orders > All purchase orders lists the order with purchase type Returned order; its product receipt and invoice journals hold the shipment and the credit note.
  • The Purchase return order created business event fires when the return order is created, if you have activated it.

When it goes wrong​

ErrorCode arrives as an integer (1 ValidationFailed, 2 DocumentNotFound, 3 InvalidStatus, 4 BusinessRule).

  • Create, ValidationFailed: ReturnItemNum missing, no lines, a line without ItemId, or a line whose Qty is missing or 0 (a quantity is never defaulted). VendAccount missing is ValidationFailed too; an unknown vendor is DocumentNotFound.
  • Create, BusinessRule: D365's own validation refused the order or a line; the reason is in Errors. Nothing is created.
  • Ship, InvalidStatus, "must be confirmed before it can be shipped": run step 2 first. The message also names the order's approval status, so you can tell an order still waiting for change-management approval.
  • Ship or credit, InvalidStatus, "is not a return order": PurchaseOrderId names an ordinary purchase order. Use Receive and invoice a purchase order for those.
  • Ship or credit, ValidationFailed: PackingSlipId (ship) or InvoiceId (credit) is missing, or PurchaseOrderId is missing.
  • Ship or credit, BusinessRule, "posted nothing": there was nothing to post, for example the return was already shipped or credited.
  • Ship or credit, BusinessRule, other: D365 refused the posting itself, for example not enough stock in the warehouse or a credit note number already used for the vendor. The D365 message is in Errors; fix the cause and send the step again (a failed request is not recorded, so its RequestId runs again).
  • DocumentNotFound: no such order in LegalEntityId.
  • Preview and retries: PreviewMode: true is refused with PreviewUnsupported. Resending a step with the same RequestId returns the recorded result and never creates or posts twice; TransientRuntime and RequestInProgress are safe to retry that way.

Reference​