Scenario: Turn a purchase requisition into a purchase order
Goal. An employee's request for goods, raised in an external system (an e-procurement portal, a service desk, an intranet form), becomes a D365 purchase requisition, goes through the requisition's approval workflow, and ends as a purchase order to the vendor. Your system creates the requisition, submits it, approves it as the workflow's approvers, and reads back the purchase order number.
When to use. Requests that must be approved before anything is ordered. If you already know what to order and from whom, create the purchase order directly and continue with Receive and invoice a purchase order, which is also the next step after this one.
Prerequisites
-
Security. The D365 user your Entra application is mapped to needs:
MGCLatticeAccountsPayableServiceMaintainforsubmitPurchaseRequisitionandconvertPurchaseRequisitionToOrder, andMGCLatticeWorkflowServiceMaintainforsubmitToWorkflowandapproveWorkItem(both in dutyMGCLatticeIntegrationServiceOperationsDuty);MGCLatticeWorkflowServiceViewforgetWorkflowStatus(dutyMGCLatticeIntegrationServiceQueryDuty).
The integration operator and administrator roles hold both duties. The standard D365 entities this page uses (
PurchaseRequisitionHeaders,PurchaseRequisitionLines,PurchaseOrderLinesV2,WorkflowWorkItems) are secured by D365's own privileges, which the Lattice roles do not grant. -
The calling user is the preparer. D365 lets only a requisition's preparer submit it, so the calling D365 user must be linked to the preparer's worker (the user's Person on System administration > Users > Users). In USMF the
Adminuser is Julia Funderburk, worker000020. -
An active requisition review workflow. A workflow of type
PurchReqReviewmust apply to the requisition (Procurement and sourcing > Setup > Procurement and sourcing workflows). USMF ships one; its review step is assigned to the users Inga and Sara. -
Workflow processing is running. The Workflow message processing batch job creates the approvers' work items after a submit. Check it is Waiting or Executing on System administration > Inquiries > Batch jobs; while it is on hold, no work item is ever created.
-
Procurement and purchasing policies. Each requisition line must pass the buying legal entity's procurement policy. In USMF the policy limits items to the Office Supplies USMF catalog (
C0001toC0004;C0001andC0003also need a color). The purchasing policy (Procurement and sourcing > Setup > Policies > Purchasing policies) decides whether approved lines become purchase orders automatically or wait for manual creation; step 5 depends on it. Number sequences for requisitions and purchase orders must exist. -
Lattice. A valid license for the write operations. To send your own requisition keys instead of D365 numbers, set up an external system (
PurchReqIdExternalKey, see Cross-reference keys).
Steps
Every service call is POST https://<your-environment>/api/services/<ServiceGroup>/<ServiceClass>/<operation>
with an OAuth 2.0 client-credentials token and the request in _request. Send a new RequestId (GUID) for each
logical request and the same one when you retry it.
-
Create the requisition and its lines (OData). Purchase requisitions are shared across legal entities, so the header has no
dataAreaId; each line names its buying legal entity.POST https://<your-environment>/data/PurchaseRequisitionHeaders{ "RequisitionName": "Keyboards for new hires", "RequisitionPurpose": "Consumption", "PreparerPersonnelNumber": "000020" }The response carries the
RequisitionNumber(for example000312). Add a line:POST https://<your-environment>/data/PurchaseRequisitionLines{ "RequisitionNumber": "000312", "RequisitionLineNumber": 1, "ItemNumber": "C0002","RequestedPurchaseQuantity": 10, "PurchasePrice": 50, "BuyingLegalEntityId": "USMF","ReceivingSiteId": "1", "ReceivingWarehouseId": "11" } -
Submit it to workflow. Two operations do this, with the same document checks as the requisition page's Submit: the requisition must be a draft with no workflow in progress, have lines, be submitted by its preparer and pass the submission rules. It moves to In review together with the workflow activation.
Operation Service and group You send DocumentIdin the answersubmitPurchaseRequisitionMGCLatticePurchaseRequisitionService,MGCLatticeAccountsPayableServiceGroupPurchReqId(orPurchReqIdExternalKey)The requisition number; the message names the workflow correlation id submitToWorkflowMGCLatticeWorkflowActionService,MGCLatticeWorkflowServiceGroupWorkflowTypeName,TableName,DocumentNumber(orRecordRecId)The workflow correlation id (lower case, no braces) POST .../api/services/MGCLatticeAccountsPayableServiceGroup/MGCLatticePurchaseRequisitionService/submitPurchaseRequisition{ "_request": { "RequestId": "5d2f8a61-3c4e-4b7a-9f10-2a6c8e1d4b93", "LegalEntityId": "USMF","UserContext": "Admin", "PurchReqId": "000312", "Comment": "Submitted from the portal" } }The
submitToWorkflowequivalent sends"WorkflowTypeName": "PurchReqReview","TableName": "PurchReqTable"and"DocumentNumber": "000312". -
Find the workflow and who must approve it. Call
getWorkflowStatus(MGCLatticeWorkflowActionService,MGCLatticeWorkflowServiceGroup) with the requisition number, the correlation id, or the requisition's RecId:{ "_request": { "RequestId": "0e7b3c55-18d2-4f6e-a1c9-77b04d2e9a10", "LegalEntityId": "USMF", "DocumentId": "000312" } }DocumentStatusis the workflow's tracking status (Pending,Completed,Cancelled,Faulted, ...).StatusDetailscarriesWorkflowCorrelationIdand onePendingWorkItem_<RecId>entry per pending work item, whose value is its assignee. The work items appear asynchronously, usually within a minute and sometimes after several, so poll until at least one is listed. The standardWorkflowWorkItemsentity ($filter=RootCorrelationId eq <correlation id>) gives the sameUserId,StatusandType. -
Approve each work item as its assignee. Call
approveWorkItem(MGCLatticeWorkflowActionService,MGCLatticeWorkflowServiceGroup).ActingUserIdis required and must be the assignee;UserContextnever selects who acts. The action runs as that user, so the workflow history records the approver.{ "_request": { "RequestId": "a41c6e02-95bd-4d1f-8e3a-c2d7f0b65e18", "LegalEntityId": "USMF","WorkflowCorrelationId": "be1322c8-5f0a-4c55-9d2e-3a7b6c1f8e04", "ActingUserId": "Inga","Comment": "Approved" } }DocumentIdis the work item's RecId. CallgetWorkflowStatusagain: if another approval work item is pending (USMF assigns the review step to Inga and Sara), approve it as its assignee too, with a newRequestId, untilDocumentStatusisCompleted. -
Get the purchase order. Read the requisition's status:
GET https://<your-environment>/data/PurchaseRequisitionHeaders?$filter=RequisitionNumber eq '000312'&$select=RequisitionStatus-
Closed: the purchasing policy creates purchase orders automatically, so D365 released the approved requisition to a purchase order on its own, shortly after the approval. Read the order from its lines:GET https://<your-environment>/data/PurchaseOrderLinesV2?$filter=PurchaseRequisitionId eq '000312' and dataAreaId eq 'USMF'&$select=PurchaseOrderNumber&cross-company=true. Do not call the conversion. -
Approved: the lines use manual purchase order creation. CallconvertPurchaseRequisitionToOrder(MGCLatticePurchaseRequisitionService,MGCLatticeAccountsPayableServiceGroup):{ "_request": { "RequestId": "c9f05b7e-2a61-4e38-b4d3-91e6a0c27f45", "LegalEntityId": "USMF", "PurchReqId": "000312" } }DocumentIdis the requisition,PostedDocumentIdthe first purchase order created, and the message lists every order the conversion created.
-
How to verify
submitPurchaseRequisition/submitToWorkflow:Successtrue,Status3 (Succeeded), andPurchaseRequisitionHeaders.RequisitionStatusisInReview.getWorkflowStatus:DocumentStatusCompletedafter the last approval, with noPendingWorkItem_entry left.- The requisition is
Approvedor, when the policy released it,Closed. - The order exists:
PurchaseOrderLinesV2rows withPurchaseRequisitionId= your requisition, or thePostedDocumentIdof the conversion inPurchaseOrderHeadersV2. - In D365: Procurement and sourcing > Purchase requisitions > All purchase requisitions shows the status and the workflow history; the order is on Procurement and sourcing > Purchase orders > All purchase orders.
- The Purchase requisition approved business event fires when the approval workflow completes, if you have activated it.
- Every call is listed on System administration > Inquiries > Lattice > Services > Service call log with its error code, message and request id.
When it goes wrong
ErrorCode arrives as an integer (1 ValidationFailed, 2 DocumentNotFound, 3 InvalidStatus, 4 BusinessRule,
11 ConfigurationMissing); Errors carries the D365 messages.
- The line is refused when you create it (OData error): the item is outside the procurement policy ("The product is no longer available") or is a product master without its dimensions. Use an item from the policy's catalog.
- Submit,
BusinessRule, "can only be submitted by its preparer": link the calling user to the preparer's worker, or create the requisition with the calling user's worker as preparer. - Submit,
BusinessRule, "has no lines" or "does not pass the submission rules": the reasons are inErrors; correct the requisition and submit again (a failed request is not recorded, so itsRequestIdruns again). - Submit,
InvalidStatus: the requisition is not a draft, or a workflow is already in progress. - Submit,
ConfigurationMissing: no activePurchReqReviewconfiguration applies to the requisition. - Approve,
InvalidStatuswithIsRetryabletrue: the workflow is pending but its work items are not created yet. Wait and retry. If they never appear, check that Workflow message processing is running and whethergetWorkflowStatusreportsFaultedwith aFaultMessagedetail. - Approve,
BusinessRule, "assigned to ...":ActingUserIdis not the assignee; the message names the assignees. Send one of them. - Approve,
ValidationFailed:ActingUserIdis missing or not an enabled user, or neitherWorkflowCorrelationIdnorWorkItemRecIdwas sent. - Approve,
BusinessRule, refused by the platform: for example the workflow parameter Prevent external work item completion stops completion from outside the work item; the reason is inErrors. - Convert,
InvalidStatus: the requisition is notApproved. When the error namesClosed, the purchasing policy has already released it (also when it happens between your status read and the call): read the order fromPurchaseOrderLinesV2.InReviewmeans the approval is not complete yet. - Convert,
ValidationFailed, "no lines left to convert": every line already has a purchase order. - Starting over.
recallWorkflow(WorkflowCorrelationId) cancels the workflow and returns the requisition toDraft; only the workflow's originator, or a user with the workflow history's Cancel, may recall it (AccessDeniedotherwise).rejectWorkItemreturns the requisition to its preparer. - Retries. None of these operations has a preview:
PreviewMode: trueis refused withPreviewUnsupported. Resending the sameRequestIdreturns the recorded result and never acts twice, so give each approval its ownRequestId; aRequestIdalready used by another operation is refused withDuplicateRequest.TransientRuntimeandRequestInProgressare safe to retry with the sameRequestId.
Reference
- API reference: sections 10 (Workflow Action Service), 18 (Purchase Requisition Service) and 20 (Status Query Operations)
- Endpoint payload specification: request payloads per operation
- Security model: privileges, duties and roles
- Cross-reference keys: sending your own requisition keys
- Trial and day-one guide: the Entra application and the first call
- Integration operations: service call log and test console
- Purchase requisition approved event
- Next: Receive and invoice a purchase order