SwimdraftPricingSign inStart free

Subscription cancellation BPMN example

Cancellation is the one customer journey that regulators, finance, and retention teams all care about at once, which makes it worth mapping precisely. Rules in several markets now require cancelling to be as easy as signing up, so the process cannot hide steps. It usually goes wrong in two ways: retention offers that block the exit and infuriate the customer, and billing that keeps charging after the account is closed.

The model is a single pool with three lanes: Customer support, Retention, and Billing. Two exclusive gateways drive it, one for the retention offer and one for whether the customer is owed credit on the final balance. Notice that the retention attempt is a single offer with a clean exit: the default path leads to cancellation, so declining the offer never traps the token in a persuasion loop.

Subscription cancellation: BPMN 2.0 diagram
Subscription cancellation 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
Cancellation requested
Ends with
Subscription retained · Subscription ended
Lanes
Customer support · Retention · Billing
Decisions
Offer accepted? · Credit owed to customer?

How to read this diagram

The flow opens in the Customer support lane when a cancellation is requested, and the agent captures the cancellation reason for later analysis. In the Retention lane, one retention offer is presented, and the gateway "Offer accepted?" resolves it: on the Yes branch a discount is applied and the process ends immediately at "Subscription retained". The default No branch respects the customer decision and moves to Billing.

Billing work then runs in a fixed order: the subscription is cancelled first, so no further charges can occur, and the final balance is calculated next. The gateway "Credit owed to customer?" checks the result: Yes triggers a refund of the unused period before confirmation, while the default No branch goes straight to it. A confirmation message from Customer support closes the process at "Subscription ended", giving the model two end states that mirror the two commercial outcomes.

BPMN elements used

ElementCountIn this diagram
Start event1Cancellation requested
End event2Subscription retained, Subscription ended
Task1Calculate final balance
User task1Capture cancellation reason
Service task3Apply retention discount, Cancel subscription, Refund unused period
Send task2Present retention offer, Confirm cancellation
Exclusive gateway2Offer accepted?, Credit owed to customer?
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_sc" name="Subscription cancellation" processRef="Process_pool_sc" />
  </bpmn2:collaboration>
  <bpmn2:process id="Process_pool_sc" isExecutable="false">
    <bpmn2:laneSet id="LaneSet_pool_sc">
      <bpmn2:lane id="lane_sc_sup" name="Customer support">
        <bpmn2:flowNodeRef>start_sc</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_sc_reason</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_sc_confirm</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>end_sc_ended</bpmn2:flowNodeRef>
      </bpmn2:lane>
      <bpmn2:lane id="lane_sc_ret" name="Retention">
        <bpmn2:flowNodeRef>t_sc_offer</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>g_sc_accept</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_sc_apply</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>end_sc_retained</bpmn2:flowNodeRef>
      </bpmn2:lane>
      <bpmn2:lane id="lane_sc_bill" name="Billing">
        <bpmn2:flowNodeRef>t_sc_cancel</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_sc_balance</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>g_sc_credit</bpmn2:flowNodeRef>
        <bpmn2:flowNodeRef>t_sc_refund</bpmn2:flowNodeRef>
      </bpmn2:lane>
    </bpmn2:laneSet>
    <bpmn2:startEvent id="start_sc" name="Cancellation requested">
      <bpmn2:outgoing>f_sc1</bpmn2:outgoing>
    </bpmn2:startEvent>
    <bpmn2:userTask id="t_sc_reason" name="Capture cancellation reason">
      <bpmn2:incoming>f_sc1</bpmn2:incoming>
      <bpmn2:outgoing>f_sc2</bpmn2:outgoing>
    </bpmn2:userTask>
    <bpmn2:sendTask id="t_sc_offer" name="Present retention offer">
      <bpmn2:incoming>f_sc2</bpmn2:incoming>
      <bpmn2:outgoing>f_sc3</bpmn2:outgoing>
    </bpmn2:sendTask>
    <bpmn2:exclusiveGateway id="g_sc_accept" name="Offer accepted?" default="f_sc5">
      <bpmn2:incoming>f_sc3</bpmn2:incoming>
      <bpmn2:outgoing>f_sc4</bpmn2:outgoing>
      <bpmn2:outgoing>f_sc5</bpmn2:outgoing>
    </bpmn2:exclusiveGateway>
    <bpmn2:serviceTask id="t_sc_apply" name="Apply retention discount">
      <bpmn2:incoming>f_sc4</bpmn2:incoming>
      <bpmn2:outgoing>f_sc6</bpmn2:outgoing>
    </bpmn2:serviceTask>
    <bpmn2:endEvent id="end_sc_retained" name="Subscription retained">
      <bpmn2:incoming>f_sc6</bpmn2:incoming>
    </bpmn2:endEvent>
    <bpmn2:serviceTask id="t_sc_cancel" name="Cancel subscription">
      <bpmn2:incoming>f_sc5</bpmn2:incoming>
      <bpmn2:outgoing>f_sc7</bpmn2:outgoing>
    </bpmn2:serviceTask>
    <bpmn2:task id="t_sc_balance" name="Calculate final balance">
      <bpmn2:incoming>f_sc7</bpmn2:incoming>
      <bpmn2:outgoing>f_sc8</bpmn2:outgoing>
    </bpmn2:task>
    <bpmn2:exclusiveGateway id="g_sc_credit" name="Credit owed to customer?" default="f_sc10">
      <bpmn2:incoming>f_sc8</bpmn2:incoming>
      <bpmn2:outgoing>f_sc9</bpmn2:outgoing>
      <bpmn2:outgoing>f_sc10</bpmn2:outgoing>
    </bpmn2:exclusiveGateway>
    <bpmn2:serviceTask id="t_sc_refund" name="Refund unused period">
      <bpmn2:incoming>f_sc9</bpmn2:incoming>
      <bpmn2:outgoing>f_sc11</bpmn2:outgoing>
    </bpmn2:serviceTask>
    <bpmn2:sendTask id="t_sc_confirm" name="Confirm cancellation">
      <bpmn2:incoming>f_sc10</bpmn2:incoming>
      <bpmn2:incoming>f_sc11</bpmn2:incoming>
      <bpmn2:outgoing>f_sc12</bpmn2:outgoing>
    </bpmn2:sendTask>
    <bpmn2:endEvent id="end_sc_ended" name="Subscription ended">
      <bpmn2:incoming>f_sc12</bpmn2:incoming>
    </bpmn2:endEvent>
    <bpmn2:sequenceFlow id="f_sc1" sourceRef="start_sc" targetRef="t_sc_reason" />
    <bpmn2:sequenceFlow id="f_sc2" sourceRef="t_sc_reason" targetRef="t_sc_offer" />
    <bpmn2:sequenceFlow id="f_sc3" sourceRef="t_sc_offer" targetRef="g_sc_accept" />
    <bpmn2:sequenceFlow id="f_sc4" name="Yes" sourceRef="g_sc_accept" targetRef="t_sc_apply">
      <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
    </bpmn2:sequenceFlow>
    <bpmn2:sequenceFlow id="f_sc5" name="No" sourceRef="g_sc_accept" targetRef="t_sc_cancel" />
    <bpmn2:sequenceFlow id="f_sc6" sourceRef="t_sc_apply" targetRef="end_sc_retained" />
    <bpmn2:sequenceFlow id="f_sc7" sourceRef="t_sc_cancel" targetRef="t_sc_balance" />
    <bpmn2:sequenceFlow id="f_sc8" sourceRef="t_sc_balance" targetRef="g_sc_credit" />
    <bpmn2:sequenceFlow id="f_sc9" name="Yes" sourceRef="g_sc_credit" targetRef="t_sc_refund">
      <bpmn2:conditionExpression xsi:type="bpmn2:tFormalExpression">Yes</bpmn2:conditionExpression>
    </bpmn2:sequenceFlow>
    <bpmn2:sequenceFlow id="f_sc10" name="No" sourceRef="g_sc_credit" targetRef="t_sc_confirm" />
    <bpmn2:sequenceFlow id="f_sc11" sourceRef="t_sc_refund" targetRef="t_sc_confirm" />
    <bpmn2:sequenceFlow id="f_sc12" sourceRef="t_sc_confirm" targetRef="end_sc_ended" />
  </bpmn2:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
      <bpmndi:BPMNShape id="pool_sc_di" bpmnElement="pool_sc" isHorizontal="true">
        <dc:Bounds x="20" y="20" width="1570" height="390" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="lane_sc_sup_di" bpmnElement="lane_sc_sup" isHorizontal="true">
        <dc:Bounds x="50" y="20" width="1540" height="130" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="lane_sc_ret_di" bpmnElement="lane_sc_ret" isHorizontal="true">
        <dc:Bounds x="50" y="150" width="1540" height="130" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="lane_sc_bill_di" bpmnElement="lane_sc_bill" isHorizontal="true">
        <dc:Bounds x="50" y="280" width="1540" height="130" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="start_sc_di" bpmnElement="start_sc">
        <dc:Bounds x="112" y="59" width="36" height="36" />
        <bpmndi:BPMNLabel><dc:Bounds x="73" y="101" width="115" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_sc_reason_di" bpmnElement="t_sc_reason">
        <dc:Bounds x="230" y="37" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_sc_offer_di" bpmnElement="t_sc_offer">
        <dc:Bounds x="380" y="167" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="g_sc_accept_di" bpmnElement="g_sc_accept">
        <dc:Bounds x="555" y="182" width="50" height="50" />
        <bpmndi:BPMNLabel><dc:Bounds x="540" y="162" width="81" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_sc_apply_di" bpmnElement="t_sc_apply">
        <dc:Bounds x="680" y="167" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_sc_retained_di" bpmnElement="end_sc_retained">
        <dc:Bounds x="862" y="189" width="36" height="36" />
        <bpmndi:BPMNLabel><dc:Bounds x="827" y="231" width="106" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_sc_cancel_di" bpmnElement="t_sc_cancel">
        <dc:Bounds x="680" y="297" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_sc_balance_di" bpmnElement="t_sc_balance">
        <dc:Bounds x="830" y="297" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="g_sc_credit_di" bpmnElement="g_sc_credit">
        <dc:Bounds x="1005" y="312" width="50" height="50" />
        <bpmndi:BPMNLabel><dc:Bounds x="966" y="292" width="128" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_sc_refund_di" bpmnElement="t_sc_refund">
        <dc:Bounds x="1130" y="297" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="t_sc_confirm_di" bpmnElement="t_sc_confirm">
        <dc:Bounds x="1280" y="37" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_sc_ended_di" bpmnElement="end_sc_ended">
        <dc:Bounds x="1462" y="59" width="36" height="36" />
        <bpmndi:BPMNLabel><dc:Bounds x="1432" y="101" width="97" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="f_sc1_di" bpmnElement="f_sc1">
        <di:waypoint x="148" y="77" />
        <di:waypoint x="230" y="77" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc2_di" bpmnElement="f_sc2">
        <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="f_sc3_di" bpmnElement="f_sc3">
        <di:waypoint x="480" y="207" />
        <di:waypoint x="555" y="207" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc4_di" bpmnElement="f_sc4">
        <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="f_sc5_di" bpmnElement="f_sc5">
        <di:waypoint x="605" y="207" />
        <di:waypoint x="660" y="207" />
        <di:waypoint x="660" y="337" />
        <di:waypoint x="680" y="337" />
        <bpmndi:BPMNLabel><dc:Bounds x="611" y="213" width="17" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc6_di" bpmnElement="f_sc6">
        <di:waypoint x="780" y="207" />
        <di:waypoint x="862" y="207" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc7_di" bpmnElement="f_sc7">
        <di:waypoint x="780" y="337" />
        <di:waypoint x="830" y="337" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc8_di" bpmnElement="f_sc8">
        <di:waypoint x="930" y="337" />
        <di:waypoint x="1005" y="337" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc9_di" bpmnElement="f_sc9">
        <di:waypoint x="1055" y="337" />
        <di:waypoint x="1130" y="337" />
        <bpmndi:BPMNLabel><dc:Bounds x="1061" y="317" width="21" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc10_di" bpmnElement="f_sc10">
        <di:waypoint x="1055" y="337" />
        <di:waypoint x="1110" y="337" />
        <di:waypoint x="1110" y="286" />
        <di:waypoint x="1260" y="286" />
        <di:waypoint x="1260" y="77" />
        <di:waypoint x="1280" y="77" />
        <bpmndi:BPMNLabel><dc:Bounds x="1061" y="343" width="17" height="14" /></bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc11_di" bpmnElement="f_sc11">
        <di:waypoint x="1230" y="337" />
        <di:waypoint x="1260" y="337" />
        <di:waypoint x="1260" y="77" />
        <di:waypoint x="1280" y="77" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="f_sc12_di" bpmnElement="f_sc12">
        <di:waypoint x="1380" y="77" />
        <di:waypoint x="1462" y="77" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn2:definitions>

Frequently asked questions

Why does the model cancel the subscription before calculating the balance?

Ordering matters in BPMN because sequence flows are commitments about time. Cancelling first guarantees the customer cannot be billed again while finance works out the closing position, which is the failure customers complain about most. Reversing the two tasks would be a valid diagram but a worse process, and the model should encode the safer order.

Should the retention offer be allowed to repeat with a loop?

You could loop back to "Present retention offer" after a No, but consumer protection rules increasingly treat repeated obstruction of cancellation as a dark pattern. A single offer with the default flow leading to cancellation is both simpler to read and easier to defend. If you must model a second offer, cap it explicitly with its own gateway.

Where would a notice period fit in this model?

Insert a timer intermediate catch event between "Offer accepted?" and "Cancel subscription", set to the contractual notice period, so the token waits before billing acts. In Swimdraft you can add the timer in the browser editor and the diagram is re-validated live, with the export still opening in Camunda Modeler or any BPMN 2.0 tool.

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