SwimdraftPricingSign inStart free

Procure to pay BPMN example

Procure to pay (P2P) runs from the moment someone in the business needs to buy something to the moment the supplier is paid. Teams map it because spend control depends on it: an unapproved requisition, a missing goods receipt, or an unmatched invoice each leaks money in a different way. The usual failure point is the gap between ordering and paying, where paperwork from three sources has to agree.

This model uses a single pool with four lanes: Requester, Procurement, Warehouse, and Accounts payable. Two exclusive gateways carry the decisions, one for requisition approval and one for the three way match, and the failed match branch loops back through a discrepancy task instead of ending the process. That loop is the modelling choice worth noticing: mismatches are normal work, not terminal errors.

Procure to pay: BPMN 2.0 diagram
Procure to pay process modelled as a BPMN 2.0 diagram

Standard BPMN 2.0 interchange XML: opens in Camunda Modeler, Signavio, Bizagi, and any other compliant tool.

The process at a glance

Starts when
Purchase need identified
Ends with
Requisition rejected · Supplier paid
Lanes
Requester · Procurement · Warehouse · Accounts payable
Decisions
Requisition approved? · Match successful?

How to read this diagram

Everything begins in the Requester lane when a purchase need is identified and a requisition is raised. Procurement reviews it, and the exclusive gateway "Requisition approved?" splits the flow: the No branch, marked as the default, notifies the requester and finishes at the "Requisition rejected" end event, while the Yes branch continues to purchase order creation. A send task passes the order to the supplier, and the Warehouse lane records the goods receipt when the delivery lands.

Accounts payable then runs the three way match, checking the supplier invoice against the purchase order and the goods receipt. At the second gateway, "Match successful?", a failed match takes the default No branch into "Resolve invoice discrepancy" and loops straight back to the match task until the figures agree. Once the Yes branch is taken, the payment is executed and the process closes at "Supplier paid".

BPMN elements used

ElementCountIn this diagram
Start event1Purchase need identified
End event2Requisition rejected, Supplier paid
Task1Record goods receipt
User task3Raise purchase requisition, Review requisition, Resolve invoice discrepancy
Service task2Create purchase order, Execute supplier payment
Send task2Notify requester of rejection, Send PO to supplier
Business rule task1Run three way match
Exclusive gateway2Requisition approved?, Match successful?
View the BPMN 2.0 XML for this diagram
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="swimdraft" exporterVersion="1.0">
  <bpmn2:collaboration id="Collaboration_1">
    <bpmn2:participant id="pool_p2p" name="Procure to pay" processRef="Process_pool_p2p" />
  </bpmn2:collaboration>
  <bpmn2:process id="Process_pool_p2p" isExecutable="false">
    <bpmn2:laneSet id="LaneSet_pool_p2p">
      <bpmn2:lane id="lane_p2p_req" name="Requester">
        <bpmn2:flowNodeRef>start_p2p</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_p2p_raise</bpmn2:flowNodeRef>
      </bpmn2:lane>
      <bpmn2:lane id="lane_p2p_proc" name="Procurement">
        <bpmn2:flowNodeRef>t_p2p_review</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>g_p2p_approve</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_p2p_notify</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>end_p2p_rejected</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_p2p_po</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_p2p_send</bpmn2:flowNodeRef>
      </bpmn2:lane>
      <bpmn2:lane id="lane_p2p_wh" name="Warehouse">
        <bpmn2:flowNodeRef>t_p2p_receive</bpmn2:flowNodeRef>
      </bpmn2:lane>
      <bpmn2:lane id="lane_p2p_ap" name="Accounts payable">
        <bpmn2:flowNodeRef>t_p2p_match</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>g_p2p_match</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_p2p_resolve</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_p2p_pay</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>end_p2p_paid</bpmn2:flowNodeRef>
      </bpmn2:lane>
    </bpmn2:laneSet>
    <bpmn2:startEvent id="start_p2p" name="Purchase need identified">
      <bpmn2:outgoing>fp2p1</bpmn2:outgoing>
    </bpmn2:startEvent>
    <bpmn2:userTask id="t_p2p_raise" name="Raise purchase requisition">
      <bpmn2:incoming>fp2p1</bpmn2:incoming>
      <bpmn2:outgoing>fp2p2</bpmn2:outgoing>
    </bpmn2:userTask>
    <bpmn2:userTask id="t_p2p_review" name="Review requisition">
      <bpmn2:incoming>fp2p2</bpmn2:incoming>
      <bpmn2:outgoing>fp2p3</bpmn2:outgoing>
    </bpmn2:userTask>
    <bpmn2:exclusiveGateway id="g_p2p_approve" name="Requisition approved?" default="fp2p5">
      <bpmn2:incoming>fp2p3</bpmn2:incoming>
      <bpmn2:outgoing>fp2p4</bpmn2:outgoing>
      <bpmn2:outgoing>fp2p5</bpmn2:outgoing>
    </bpmn2:exclusiveGateway>
    <bpmn2:sendTask id="t_p2p_notify" name="Notify requester of rejection">
      <bpmn2:incoming>fp2p5</bpmn2:incoming>
      <bpmn2:outgoing>fp2p6</bpmn2:outgoing>
    </bpmn2:sendTask>
    <bpmn2:endEvent id="end_p2p_rejected" name="Requisition rejected">
      <bpmn2:incoming>fp2p6</bpmn2:incoming>
    </bpmn2:endEvent>
    <bpmn2:serviceTask id="t_p2p_po" name="Create purchase order">
      <bpmn2:incoming>fp2p4</bpmn2:incoming>
      <bpmn2:outgoing>fp2p7</bpmn2:outgoing>
    </bpmn2:serviceTask>
    <bpmn2:sendTask id="t_p2p_send" name="Send PO to supplier">
      <bpmn2:incoming>fp2p7</bpmn2:incoming>
      <bpmn2:outgoing>fp2p8</bpmn2:outgoing>
    </bpmn2:sendTask>
    <bpmn2:task id="t_p2p_receive" name="Record goods receipt">
      <bpmn2:incoming>fp2p8</bpmn2:incoming>
      <bpmn2:outgoing>fp2p9</bpmn2:outgoing>
    </bpmn2:task>
    <bpmn2:businessRuleTask id="t_p2p_match" name="Run three way match">
      <bpmn2:incoming>fp2p9</bpmn2:incoming>
      <bpmn2:incoming>fp2p13</bpmn2:incoming>
      <bpmn2:outgoing>fp2p10</bpmn2:outgoing>
    </bpmn2:businessRuleTask>
    <bpmn2:exclusiveGateway id="g_p2p_match" name="Match successful?" default="fp2p12">
      <bpmn2:incoming>fp2p10</bpmn2:incoming>
      <bpmn2:outgoing>fp2p11</bpmn2:outgoing>
      <bpmn2:outgoing>fp2p12</bpmn2:outgoing>
    </bpmn2:exclusiveGateway>
    <bpmn2:userTask id="t_p2p_resolve" name="Resolve invoice discrepancy">
      <bpmn2:incoming>fp2p12</bpmn2:incoming>
      <bpmn2:outgoing>fp2p13</bpmn2:outgoing>
    </bpmn2:userTask>
    <bpmn2:serviceTask id="t_p2p_pay" name="Execute supplier payment">
      <bpmn2:incoming>fp2p11</bpmn2:incoming>
      <bpmn2:outgoing>fp2p14</bpmn2:outgoing>
    </bpmn2:serviceTask>
    <bpmn2:endEvent id="end_p2p_paid" name="Supplier paid">
      <bpmn2:incoming>fp2p14</bpmn2:incoming>
    </bpmn2:endEvent>
    <bpmn2:sequenceFlow id="fp2p1" sourceRef="start_p2p" targetRef="t_p2p_raise" />
    <bpmn2:sequenceFlow id="fp2p2" sourceRef="t_p2p_raise" targetRef="t_p2p_review" />
    <bpmn2:sequenceFlow id="fp2p3" sourceRef="t_p2p_review" targetRef="g_p2p_approve" />
    <bpmn2:sequenceFlow id="fp2p4" name="Yes" sourceRef="g_p2p_approve" targetRef="t_p2p_po">
      <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
    </bpmn2:sequenceFlow>
    <bpmn2:sequenceFlow id="fp2p5" name="No" sourceRef="g_p2p_approve" targetRef="t_p2p_notify" />
    <bpmn2:sequenceFlow id="fp2p6" sourceRef="t_p2p_notify" targetRef="end_p2p_rejected" />
    <bpmn2:sequenceFlow id="fp2p7" sourceRef="t_p2p_po" targetRef="t_p2p_send" />
    <bpmn2:sequenceFlow id="fp2p8" sourceRef="t_p2p_send" targetRef="t_p2p_receive" />
    <bpmn2:sequenceFlow id="fp2p9" sourceRef="t_p2p_receive" targetRef="t_p2p_match" />
    <bpmn2:sequenceFlow id="fp2p10" sourceRef="t_p2p_match" targetRef="g_p2p_match" />
    <bpmn2:sequenceFlow id="fp2p11" name="Yes" sourceRef="g_p2p_match" targetRef="t_p2p_pay">
      <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
    </bpmn2:sequenceFlow>
    <bpmn2:sequenceFlow id="fp2p12" name="No" sourceRef="g_p2p_match" targetRef="t_p2p_resolve" />
    <bpmn2:sequenceFlow id="fp2p13" sourceRef="t_p2p_resolve" targetRef="t_p2p_match" />
    <bpmn2:sequenceFlow id="fp2p14" sourceRef="t_p2p_pay" targetRef="end_p2p_paid" />
  </bpmn2:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
      <bpmndi:BPMNShape id="pool_p2p_di" bpmnElement="pool_p2p" isHorizontal="true">
        <dc:Bounds x="20" y="20" width="1720" height="740" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="lane_p2p_req_di" bpmnElement="lane_p2p_req" isHorizontal="true">
        <dc:Bounds x="50" y="20" width="1690" height="130" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="lane_p2p_proc_di" bpmnElement="lane_p2p_proc" isHorizontal="true">
        <dc:Bounds x="50" y="150" width="1690" height="240" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="lane_p2p_wh_di" bpmnElement="lane_p2p_wh" isHorizontal="true">
        <dc:Bounds x="50" y="390" width="1690" height="130" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="lane_p2p_ap_di" bpmnElement="lane_p2p_ap" isHorizontal="true">
        <dc:Bounds x="50" y="520" width="1690" height="240" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="start_p2p_di" bpmnElement="start_p2p">
        <dc:Bounds x="112" y="59" width="36" height="36" />
        <bpmndi:BPMNLabel><dc:Bounds x="68" y="101" width="124" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_raise_di" bpmnElement="t_p2p_raise">
        <dc:Bounds x="230" y="37" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_review_di" bpmnElement="t_p2p_review">
        <dc:Bounds x="380" y="167" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="g_p2p_approve_di" bpmnElement="g_p2p_approve">
        <dc:Bounds x="555" y="182" width="50" height="50" />
        <bpmndi:BPMNLabel><dc:Bounds x="524" y="162" width="112" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_notify_di" bpmnElement="t_p2p_notify">
        <dc:Bounds x="680" y="277" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_p2p_rejected_di" bpmnElement="end_p2p_rejected">
        <dc:Bounds x="862" y="299" width="36" height="36" />
        <bpmndi:BPMNLabel><dc:Bounds x="831" y="341" width="99" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_po_di" bpmnElement="t_p2p_po">
        <dc:Bounds x="680" y="167" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_send_di" bpmnElement="t_p2p_send">
        <dc:Bounds x="830" y="167" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_receive_di" bpmnElement="t_p2p_receive">
        <dc:Bounds x="980" y="407" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_match_di" bpmnElement="t_p2p_match">
        <dc:Bounds x="1130" y="537" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="g_p2p_match_di" bpmnElement="g_p2p_match">
        <dc:Bounds x="1305" y="552" width="50" height="50" />
        <bpmndi:BPMNLabel><dc:Bounds x="1284" y="532" width="93" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_resolve_di" bpmnElement="t_p2p_resolve">
        <dc:Bounds x="1430" y="647" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_p2p_pay_di" bpmnElement="t_p2p_pay">
        <dc:Bounds x="1430" y="537" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_p2p_paid_di" bpmnElement="end_p2p_paid">
        <dc:Bounds x="1612" y="559" width="36" height="36" />
        <bpmndi:BPMNLabel><dc:Bounds x="1597" y="601" width="67" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="fp2p1_di" bpmnElement="fp2p1">
        <di:waypoint x="148" y="77" />
        <di:waypoint x="230" y="77" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p2_di" bpmnElement="fp2p2">
        <di:waypoint x="330" y="77" />
        <di:waypoint x="360" y="77" />
        <di:waypoint x="360" y="207" />
        <di:waypoint x="380" y="207" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p3_di" bpmnElement="fp2p3">
        <di:waypoint x="480" y="207" />
        <di:waypoint x="555" y="207" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p4_di" bpmnElement="fp2p4">
        <di:waypoint x="605" y="207" />
        <di:waypoint x="680" y="207" />
        <bpmndi:BPMNLabel><dc:Bounds x="611" y="187" width="21" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p5_di" bpmnElement="fp2p5">
        <di:waypoint x="605" y="207" />
        <di:waypoint x="660" y="207" />
        <di:waypoint x="660" y="317" />
        <di:waypoint x="680" y="317" />
        <bpmndi:BPMNLabel><dc:Bounds x="611" y="213" width="17" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p6_di" bpmnElement="fp2p6">
        <di:waypoint x="780" y="317" />
        <di:waypoint x="862" y="317" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p7_di" bpmnElement="fp2p7">
        <di:waypoint x="780" y="207" />
        <di:waypoint x="830" y="207" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p8_di" bpmnElement="fp2p8">
        <di:waypoint x="930" y="207" />
        <di:waypoint x="960" y="207" />
        <di:waypoint x="960" y="447" />
        <di:waypoint x="980" y="447" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p9_di" bpmnElement="fp2p9">
        <di:waypoint x="1080" y="447" />
        <di:waypoint x="1110" y="447" />
        <di:waypoint x="1110" y="577" />
        <di:waypoint x="1130" y="577" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p10_di" bpmnElement="fp2p10">
        <di:waypoint x="1230" y="577" />
        <di:waypoint x="1305" y="577" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p11_di" bpmnElement="fp2p11">
        <di:waypoint x="1355" y="577" />
        <di:waypoint x="1430" y="577" />
        <bpmndi:BPMNLabel><dc:Bounds x="1361" y="557" width="21" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p12_di" bpmnElement="fp2p12">
        <di:waypoint x="1355" y="577" />
        <di:waypoint x="1410" y="577" />
        <di:waypoint x="1410" y="687" />
        <di:waypoint x="1430" y="687" />
        <bpmndi:BPMNLabel><dc:Bounds x="1361" y="583" width="17" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p13_di" bpmnElement="fp2p13">
        <di:waypoint x="1530" y="687" />
        <di:waypoint x="1560" y="687" />
        <di:waypoint x="1560" y="742" />
        <di:waypoint x="1110" y="742" />
        <di:waypoint x="1110" y="577" />
        <di:waypoint x="1130" y="577" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="fp2p14_di" bpmnElement="fp2p14">
        <di:waypoint x="1530" y="577" />
        <di:waypoint x="1612" y="577" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn2:definitions>

Frequently asked questions

Why is the supplier not modelled as a second pool?

The diagram deliberately stays inside one organisation, so the supplier only appears indirectly through the send task and the goods receipt. To model the conversation explicitly, add a second pool as a black box with no internal detail and connect it with message flows from "Send PO to supplier". Keeping it out keeps the diagram focused on internal handoffs.

Why does the failed match loop back instead of ending the process?

A mismatched invoice is routine work, not a dead end, so the No branch routes through "Resolve invoice discrepancy" and rejoins the match task. Ending the process there would strand real invoices that just need a correction. BPMN handles this kind of rework loop naturally, provided every node still sits on a path to an end event.

Why is the three way match a business rule task?

The match is a pure decision over data: compare the invoice, purchase order, and goods receipt, then report whether they agree within tolerance. BPMN reserves the business rule task type for exactly this, evaluation by a rules engine or decision table. If your organisation matches invoices by hand, change it to a user task and the flow still validates.

Related BPMN examples

Generate your own version of this diagram

Describe how the process works in your organisation: plain English, meeting notes, a transcript, or a spreadsheet. Swimdraft turns it into a spec-validated BPMN 2.0 diagram you can edit in the browser and export as .bpmn, SVG, or PNG.

Start free

No credit card required