Leave request BPMN example
Leave requests are small, frequent, and irritating when they go wrong: an employee books flights before approval, a manager approves leave the balance does not cover, or two people in a two person team end up off in the same week. Teams map the process to fix the ordering, because most of the pain comes from checks happening after decisions instead of before them.
The model is a single pool with Employee, Line manager, and HR lanes. Two exclusive gateways structure the flow: a balance check that runs before the manager ever sees the request, and the approval decision itself. The choice worth noticing is the business rule task for the balance check, signalling that this step is a lookup against policy, not a judgement call, and is a strong candidate for automation.
Standard BPMN 2.0 interchange XML: opens in Camunda Modeler, Signavio, Bizagi, and any other compliant tool.
The process at a glance
How to read this diagram
An employee opens the flow by choosing dates, marked by the "Leave dates chosen" start event, and submitting the request. HR checks the leave balance with a business rule task, feeding the gateway "Balance sufficient?". Its No branch, the default, routes to "Notify employee of refusal" and the "Request declined" end event, so requests that cannot possibly be granted never reach the manager.
Requests that survive the balance check land with the Line manager, who reviews cover and workload before the "Request approved?" gateway. A No answer joins the same refusal notification, keeping decline communication in one place. On Yes, HR records the leave in the system and confirms the booking to the employee, ending at "Leave booked". Every request therefore ends in exactly one of two clearly named states.
BPMN elements used
| Element | Count | In this diagram |
|---|---|---|
| Start event | 1 | Leave dates chosen |
| End event | 2 | Request declined, Leave booked |
| User task | 2 | Submit leave request, Review leave request |
| Service task | 1 | Record leave in system |
| Send task | 2 | Notify employee of refusal, Confirm booking |
| Business rule task | 1 | Check leave balance |
| Exclusive gateway | 2 | Balance sufficient?, Request approved? |
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_lv" name="Leave request" processRef="Process_pool_lv" />
</bpmn2:collaboration>
<bpmn2:process id="Process_pool_lv" isExecutable="false">
<bpmn2:laneSet id="LaneSet_pool_lv">
<bpmn2:lane id="lane_lv_emp" name="Employee">
<bpmn2:flowNodeRef>start_lv</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_lv_submit</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_lv_mgr" name="Line manager">
<bpmn2:flowNodeRef>t_lv_review</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>g_lv_appr</bpmn2:flowNodeRef>
</bpmn2:lane>
<bpmn2:lane id="lane_lv_hr" name="HR">
<bpmn2:flowNodeRef>t_lv_balance</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>g_lv_balance</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_lv_decline</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>end_lv_declined</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_lv_record</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>t_lv_confirm</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>end_lv_booked</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:startEvent id="start_lv" name="Leave dates chosen">
<bpmn2:outgoing>flv1</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:userTask id="t_lv_submit" name="Submit leave request">
<bpmn2:incoming>flv1</bpmn2:incoming>
<bpmn2:outgoing>flv2</bpmn2:outgoing>
</bpmn2:userTask>
<bpmn2:businessRuleTask id="t_lv_balance" name="Check leave balance">
<bpmn2:incoming>flv2</bpmn2:incoming>
<bpmn2:outgoing>flv3</bpmn2:outgoing>
</bpmn2:businessRuleTask>
<bpmn2:exclusiveGateway id="g_lv_balance" name="Balance sufficient?" default="flv5">
<bpmn2:incoming>flv3</bpmn2:incoming>
<bpmn2:outgoing>flv4</bpmn2:outgoing>
<bpmn2:outgoing>flv5</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:sendTask id="t_lv_decline" name="Notify employee of refusal">
<bpmn2:incoming>flv5</bpmn2:incoming>
<bpmn2:incoming>flv9</bpmn2:incoming>
<bpmn2:outgoing>flv6</bpmn2:outgoing>
</bpmn2:sendTask>
<bpmn2:endEvent id="end_lv_declined" name="Request declined">
<bpmn2:incoming>flv6</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:userTask id="t_lv_review" name="Review leave request">
<bpmn2:incoming>flv4</bpmn2:incoming>
<bpmn2:outgoing>flv7</bpmn2:outgoing>
</bpmn2:userTask>
<bpmn2:exclusiveGateway id="g_lv_appr" name="Request approved?" default="flv9">
<bpmn2:incoming>flv7</bpmn2:incoming>
<bpmn2:outgoing>flv8</bpmn2:outgoing>
<bpmn2:outgoing>flv9</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:serviceTask id="t_lv_record" name="Record leave in system">
<bpmn2:incoming>flv8</bpmn2:incoming>
<bpmn2:outgoing>flv10</bpmn2:outgoing>
</bpmn2:serviceTask>
<bpmn2:sendTask id="t_lv_confirm" name="Confirm booking">
<bpmn2:incoming>flv10</bpmn2:incoming>
<bpmn2:outgoing>flv11</bpmn2:outgoing>
</bpmn2:sendTask>
<bpmn2:endEvent id="end_lv_booked" name="Leave booked">
<bpmn2:incoming>flv11</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="flv1" sourceRef="start_lv" targetRef="t_lv_submit" />
<bpmn2:sequenceFlow id="flv2" sourceRef="t_lv_submit" targetRef="t_lv_balance" />
<bpmn2:sequenceFlow id="flv3" sourceRef="t_lv_balance" targetRef="g_lv_balance" />
<bpmn2:sequenceFlow id="flv4" name="Yes" sourceRef="g_lv_balance" targetRef="t_lv_review">
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="flv5" name="No" sourceRef="g_lv_balance" targetRef="t_lv_decline" />
<bpmn2:sequenceFlow id="flv6" sourceRef="t_lv_decline" targetRef="end_lv_declined" />
<bpmn2:sequenceFlow id="flv7" sourceRef="t_lv_review" targetRef="g_lv_appr" />
<bpmn2:sequenceFlow id="flv8" name="Yes" sourceRef="g_lv_appr" targetRef="t_lv_record">
<bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="flv9" name="No" sourceRef="g_lv_appr" targetRef="t_lv_decline" />
<bpmn2:sequenceFlow id="flv10" sourceRef="t_lv_record" targetRef="t_lv_confirm" />
<bpmn2:sequenceFlow id="flv11" sourceRef="t_lv_confirm" targetRef="end_lv_booked" />
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
<bpmndi:BPMNShape id="pool_lv_di" bpmnElement="pool_lv" isHorizontal="true">
<dc:Bounds x="20" y="20" width="1420" height="500" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="lane_lv_emp_di" bpmnElement="lane_lv_emp" isHorizontal="true">
<dc:Bounds x="50" y="20" width="1390" height="130" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="lane_lv_mgr_di" bpmnElement="lane_lv_mgr" isHorizontal="true">
<dc:Bounds x="50" y="150" width="1390" height="130" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="lane_lv_hr_di" bpmnElement="lane_lv_hr" isHorizontal="true">
<dc:Bounds x="50" y="280" width="1390" height="240" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="start_lv_di" bpmnElement="start_lv">
<dc:Bounds x="112" y="59" width="36" height="36" />
<bpmndi:BPMNLabel><dc:Bounds x="80" y="101" width="101" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_lv_submit_di" bpmnElement="t_lv_submit">
<dc:Bounds x="230" y="37" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_lv_balance_di" bpmnElement="t_lv_balance">
<dc:Bounds x="380" y="297" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="g_lv_balance_di" bpmnElement="g_lv_balance">
<dc:Bounds x="555" y="312" width="50" height="50" />
<bpmndi:BPMNLabel><dc:Bounds x="533" y="292" width="95" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_lv_decline_di" bpmnElement="t_lv_decline">
<dc:Bounds x="980" y="407" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="end_lv_declined_di" bpmnElement="end_lv_declined">
<dc:Bounds x="1162" y="429" width="36" height="36" />
<bpmndi:BPMNLabel><dc:Bounds x="1137" y="471" width="87" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_lv_review_di" bpmnElement="t_lv_review">
<dc:Bounds x="680" y="167" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="g_lv_appr_di" bpmnElement="g_lv_appr">
<dc:Bounds x="855" y="182" width="50" height="50" />
<bpmndi:BPMNLabel><dc:Bounds x="831" y="162" width="98" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_lv_record_di" bpmnElement="t_lv_record">
<dc:Bounds x="980" y="297" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="t_lv_confirm_di" bpmnElement="t_lv_confirm">
<dc:Bounds x="1130" y="297" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="end_lv_booked_di" bpmnElement="end_lv_booked">
<dc:Bounds x="1312" y="319" width="36" height="36" />
<bpmndi:BPMNLabel><dc:Bounds x="1294" y="361" width="72" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="flv1_di" bpmnElement="flv1">
<di:waypoint x="148" y="77" />
<di:waypoint x="230" y="77" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv2_di" bpmnElement="flv2">
<di:waypoint x="330" y="77" />
<di:waypoint x="360" y="77" />
<di:waypoint x="360" y="337" />
<di:waypoint x="380" y="337" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv3_di" bpmnElement="flv3">
<di:waypoint x="480" y="337" />
<di:waypoint x="555" y="337" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv4_di" bpmnElement="flv4">
<di:waypoint x="605" y="337" />
<di:waypoint x="660" y="337" />
<di:waypoint x="660" y="207" />
<di:waypoint x="680" y="207" />
<bpmndi:BPMNLabel><dc:Bounds x="611" y="317" width="21" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv5_di" bpmnElement="flv5">
<di:waypoint x="605" y="337" />
<di:waypoint x="960" y="337" />
<di:waypoint x="960" y="447" />
<di:waypoint x="980" y="447" />
<bpmndi:BPMNLabel><dc:Bounds x="611" y="343" width="17" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv6_di" bpmnElement="flv6">
<di:waypoint x="1080" y="447" />
<di:waypoint x="1162" y="447" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv7_di" bpmnElement="flv7">
<di:waypoint x="780" y="207" />
<di:waypoint x="855" y="207" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv8_di" bpmnElement="flv8">
<di:waypoint x="905" y="207" />
<di:waypoint x="960" y="207" />
<di:waypoint x="960" y="337" />
<di:waypoint x="980" y="337" />
<bpmndi:BPMNLabel><dc:Bounds x="911" y="187" width="21" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv9_di" bpmnElement="flv9">
<di:waypoint x="905" y="207" />
<di:waypoint x="960" y="207" />
<di:waypoint x="960" y="447" />
<di:waypoint x="980" y="447" />
<bpmndi:BPMNLabel><dc:Bounds x="911" y="213" width="17" height="14" /></bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv10_di" bpmnElement="flv10">
<di:waypoint x="1080" y="337" />
<di:waypoint x="1130" y="337" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="flv11_di" bpmnElement="flv11">
<di:waypoint x="1230" y="337" />
<di:waypoint x="1312" y="337" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>Frequently asked questions
Why check the balance before the manager reviews the request?
Ordering is the main design decision in this process. Putting the automated balance check first means managers only spend time on requests that are actually grantable, and employees get instant refusals for impossible requests. If your policy lets managers approve negative balances, swap the order and make the balance check advisory instead.
What makes "Check leave balance" a business rule task rather than a user task?
The step applies a fixed policy (accrued days minus days taken and requested) with no human discretion, which is exactly what the business rule task type is for. Marking it this way tells readers the step is deterministic, and tells any future automation project where the quick win is.
How would I add a rule for overlapping absences in the same team?
Add a second condition to the manager stage: either broaden the existing "Request approved?" gateway so cover problems are one reason for a No, or insert a dedicated gateway such as "Team cover adequate?" before it. Keep each gateway to a single question; two small decisions read better than one overloaded one.
Related BPMN examples
Employee onboarding
An employee onboarding process diagram in BPMN 2.0: background checks, parallel IT setup, and induction. View the swimlane diagram and download the .bpmn file free.
Employee offboarding
Employee offboarding as a BPMN 2.0 diagram: handover planning, a last day timer, parallel access revocation, and final pay. Download the .bpmn file free.
Recruitment
A recruitment process in BPMN 2.0: screening, interviews, offer, and a candidate pool with message flows. View the diagram and download the .bpmn file free.
Performance review
A performance review process in BPMN 2.0: parallel self and manager assessments, a review meeting, and an objectives rework loop. Download the .bpmn file free.
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 freeNo credit card required