Skip to main content

Scenario: Ship a transfer order and receive it at the other warehouse

Goal. Move stock between two warehouses through a transfer order, with D365 updated at the two moments that matter: when the goods leave the shipping warehouse (shipment, stock goes in transit) and when they arrive at the receiving warehouse (receipt). Your warehouse system reports each event and Lattice posts it on the transfer order, for the whole order or for the lines and quantities you name.

When to use. A transfer order exists in D365 (created on the page or through the standard transfer order entities) and a warehouse or transport system knows what was shipped and received, including partial shipments. For an immediate move with no in-transit period, post a transfer journal instead (Inventory journals).

Prerequisites​

  1. Security. The caller needs the privilege MGCLatticeInventoryServiceMaintain, in the duty MGCLatticeIntegrationServiceOperationsDuty of MGCLatticeIntegrationAdministratorRole and MGCLatticeIntegrationOperatorRole (Security model). Creating the order and reading it back through the standard D365 entities needs the standard D365 access to them.
  2. D365 configuration. The two warehouses are set up for transfer orders (the shipping warehouse has a transit warehouse), the transfer order number sequences exist, and the shipping warehouse holds on-hand stock for every line you ship. In USMF: site 1, warehouse 11 (Raw Materials) to warehouse 13 (Finished Goods), item D0001. Stock can be put on hand with a movement journal (Inventory journals).
  3. Lattice. A valid Lattice license. To send your own order, line or item keys, register the external system and the keys (Use your own keys).

Steps​

Both operations belong to MGCLatticeTransferOrderPostingService in the service group MGCLatticeInventoryServiceGroup: POST https://<your-environment>/api/services/MGCLatticeInventoryServiceGroup/MGCLatticeTransferOrderPostingService/<operation>.

  1. Create the transfer order (if your system does not already have one). On the page: Inventory management > Outbound orders > Transfer order. Through OData, create the header, then a line with the number the header returns:

    POST https://<your-environment>/data/TransferOrderHeaders
    { "dataAreaId": "USMF", "ShippingWarehouseId": "11", "ReceivingWarehouseId": "13" }

    POST https://<your-environment>/data/TransferOrderLines
    { "dataAreaId": "USMF", "TransferOrderNumber": "TO-000789", "ItemNumber": "D0001", "TransferQuantity": 5 }

    Keep TransferOrderNumber: every later call needs it.

  2. Ship it (shipTransferOrder). Two ways:

    • The whole order: send no Lines. Everything still to ship is shipped.
    • Selected lines: send Lines. Only the selected lines ship, each for its Qty (the "Ship now" quantity). A line is selected unless it says IsSelected: false. A request line finds its transfer line by ItemId, plus InventDimId and LineNum when you send them (InventDimId is the transfer line's own dimension: the shipping site and warehouse, USMF 000031 for site 1, warehouse 11).
    {
    "_request": {
    "RequestId": "2d4f6a8c-0e1b-4d3f-a5c7-e9b1d3f5a702",
    "LegalEntityId": "USMF",
    "UserContext": "Admin",
    "TransferOrderId": "TO-000789",
    "PostingDate": "2026-10-07",
    "Lines": [ { "ItemId": "D0001", "InventDimId": "000031", "Qty": 5, "IsSelected": true } ]
    }
    }

    The response returns the transfer order in DocumentId and the voucher of the shipment journal it posted in PostedDocumentId. Ship the rest later with another call and a new RequestId.

  3. Receive it (receiveTransferOrder) when the goods arrive. Without Lines everything shipped and not yet received is received; with Lines, only the selected lines and their Qty (the "Receive now" quantity).

    {
    "_request": {
    "RequestId": "7b9d1f3a-5c7e-4a9b-b1d3-f5a7c9e1b324",
    "LegalEntityId": "USMF",
    "UserContext": "Admin",
    "TransferOrderId": "TO-000789",
    "PostingDate": "2026-10-07",
    "Lines": [ { "ItemId": "D0001", "InventDimId": "000031", "Qty": 5, "IsSelected": true } ]
    }
    }

    A receipt line matches its transfer line the same way, so InventDimId is again the transfer line's own (shipping) dimension. PostedDocumentId is the voucher of the receipt journal.

PostingDate defaults to today. To ship or receive many orders in one call, use shipTransferOrderBatch and receiveTransferOrderBatch (Batch and async operations).

How to verify​

  • Response. Success true, Status 3, DocumentId = the transfer order, PostedDocumentId = the shipment or receipt voucher, Message Transfer order TO-000789 shipped. or ... received. An update that posts no journal is never reported as a success.
  • OData. TransferOrderHeaders (TransferOrderNumber) shows TransferOrderStatus Shipped once everything is shipped and Received once everything is received; a partial shipment leaves it at Created. TransferOrderLines shows ShippedQuantity, ReceivedQuantity, RemainingShippedQuantity and RemainingReceivedQuantity per line. Use ?cross-company=true and filter on dataAreaId to read a legal entity other than the caller's default company.
  • Stock. LatticeInventoryOnHands shows the quantity leaving warehouse 11 at shipment and arriving at warehouse 13 at receipt.
  • In D365. Inventory management > Outbound orders > Transfer order: the order's status and its lines' shipped and received quantities.
  • Call history. System administration > Inquiries > Lattice > Services > Service call log.
  • Events. The Transfer order shipped and Transfer order received business events fire when the whole order reaches Shipped or Received (not on a partial update); Inventory on-hand changed fires for each warehouse whose stock changed (React to business events).

When it goes wrong​

Message is a summary, for example Transfer order shipment failed due to validation or business rule constraints.; Errors carries the reason.

No line selected. A request that carries lines but selects none is refused before the order is read, so a request with lines never ships or receives the whole order by accident:

{
"_request": {
"RequestId": "4e6a8c0e-2b4d-4f6a-8c0e-2b4d6f8a0c19",
"LegalEntityId": "USMF",
"TransferOrderId": "TO-000789",
"Lines": [ { "ItemId": "D0001", "Qty": 1, "IsSelected": false } ]
}
}

The answer is Success false, Status 4, ErrorCode 1 (ValidationFailed), and Errors reads:

The request carries lines but none has IsSelected set: select the lines to post, or send no lines to post the whole order.

Nothing is posted. Select at least one line, or send no Lines to post the whole order.

ErrorCodeTypical causeWhat to do
ValidationFailedTransferOrderId is required.; no line selected (above); Request line 1 has quantity 0: the quantity to post must be greater than zero.; an empty line; an external key that does not resolveFix the request; nothing was posted.
DocumentNotFoundTransfer order X was not found.; a request line that matches no transfer line (Transfer order X has no line for item D0001 (dimension 000031) to update.)Check the order number, item, dimension and line number.
BusinessRuleD365 refused the update, for example no on-hand at the shipping warehouse or more to receive than is in transit; or Transfer order X: the update posted nothing. Check the quantities left to ship or receive. when nothing is left to ship or receiveFix the stock or quantities named in Errors, then send a new request.
PreviewUnsupportedPreviewMode trueThese operations have no preview.
TransientRuntimeA runtime fault (IsRetryable true); deadlocks and update conflicts are retried by the service firstResend with the same RequestId.
DuplicateRequest / RequestInProgress / LicenseNotValidSee API referenceUse a new RequestId / wait and retry / renew the license.

Retries never post twice. The shipment or receipt and the request's idempotency record commit together, so resending a successful request with the same RequestId returns the recorded result and voucher without shipping again. A failed request records no result and can be resent once the cause is fixed. These operations are synchronous; failures show on the Failed service calls (24 h) tile of the Integration operations workspace, not in the dead-letter queue.

Reference​