BPMN 2.0 Elements

Priostack supports the BPMN 2.0 specification. This page is the complete reference for all supported elements, including their XML representation and usage notes, and says what each element does on the hosted service.

The XML snippets are fragments. Paste them inside a <process> of a <definitions> element that declares the namespaces they use: xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL", xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" and xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance". Write &lt; for < inside a condition, as the examples do: a raw < is not XML, and the deploy answers 422.

Start Events

ElementSymbolDescription
None Start Event○Process begins immediately when started via API (POST /api/v1/process-instances). No trigger required.
Message Start Event✉○Accepted at deploy and read as a none start event: on the hosted service no message starts a process, because there is no message API.
Timer Start Event⏱○Accepted at deploy and read as a none start event: nothing is scheduled. Start instances through the API, from your own scheduler.
Signal Start Event△○Accepted at deploy and read as a none start event: there is no signal broadcast API.
<!-- None Start Event -->
<startEvent id="start" name="Order Received" />

End Events

ElementSymbolDescription
None End Event●Process path terminates normally. If all tokens reach end events, the instance completes.
Message End Event✉●Read as a none end event: no message is sent. Use a service task and a worker to notify another system.
Error End Event✖●Read as a none end event today: it does not throw the error, so no error boundary event catches it.
Terminate End Event⬛●Immediately terminates all running paths in the current scope, not just the current token.
Compensation End Event◁●Runs the compensation handlers of the activities that completed, in reverse order, then ends (see Boundary Events).
<!-- Terminate End Event -->
<endEvent id="abort" name="Order Cancelled">
  <terminateEventDefinition />
</endEvent>

Tasks

ElementDescription
Service TaskExecuted by an external worker. The engine creates a job; the worker activates and completes it. The job type is zeebe:taskDefinition type="...", else the task name, else its id; retries (1 or more, default 3) sets the attempts. zeebe:ioMapping is not read: every job carries all of the instance's variables.
User TaskA job of type userTask for a human, completed through the Tasklist (POST /api/v1/tasks/{id}/complete, 1 credit), GraphQL completeTask (free) or the jobs API. The zeebe:userTask extension (assignee, candidate groups, due date) is not read; assign with POST /api/v1/tasks/{id}/assign.
Business Rule TaskEvaluates a deployed DMN decision inline, named by zeebe:calledDecision decisionId; no worker. See DMN Elements.
Script TaskNot run inline: the engine creates a worker job of type script:<name or id> (or the zeebe:taskDefinition type when one is given), and your worker runs the logic.
Send TaskA worker job of type sendTask: your worker does the sending.
Receive TaskWith a messageRef, a worker job of type message:<message name>; without one, receiveTask. The hosted API has no message correlation route, so a worker completes it, with no correlation-key matching.
Manual Task / TaskWorker jobs of type manualTask and task.
Call ActivityRuns the process named in its calledElement attribute inside the same instance, with the same variables, when that process was deployed before the caller. Otherwise it is a worker job of type callActivity:<name>. zeebe:calledElement and zeebe:ioMapping are not read.
<!-- Service Task -->
<serviceTask id="validateOrder" name="Validate Order">
  <extensionElements>
    <zeebe:taskDefinition type="validate-order" retries="3" />
  </extensionElements>
</serviceTask>

<!-- User Task -->
<userTask id="reviewTask" name="Review Order" />

<!-- Business Rule Task -->
<businessRuleTask id="applyDiscount" name="Calculate Discount">
  <extensionElements>
    <zeebe:calledDecision decisionId="discount" />
  </extensionElements>
</businessRuleTask>

<!-- Call Activity: runs the deployed process "payment-process" -->
<callActivity id="callPayment" name="Process Payment" calledElement="payment-process" />

Gateways

ElementSymbolDescription
Exclusive Gateway (XOR)✕Exactly one outgoing path is taken. Each sequence flow has a FEEL condition; the first true condition wins. A default flow handles the fallback case.
Parallel Gateway (AND)+All outgoing paths are activated simultaneously (split). When used as a join, waits for all incoming tokens before continuing.
Inclusive Gateway (OR)○One or more outgoing paths are taken based on FEEL conditions. The join waits for all activated paths.
Event-Based Gateway◇Waits for the first of several events (messages, timers, signals) to occur, then follows that path.
<!-- Exclusive Gateway -->
<exclusiveGateway id="checkAmount" name="Amount OK?" />
<sequenceFlow id="toApprove" sourceRef="checkAmount" targetRef="approve">
  <conditionExpression>=amount &lt;= 1000</conditionExpression>
</sequenceFlow>
<sequenceFlow id="toManager" sourceRef="checkAmount" targetRef="managerApproval">
  <conditionExpression>=amount &gt; 1000</conditionExpression>
</sequenceFlow>

<!-- Parallel Gateway (split) -->
<parallelGateway id="splitTasks" name="Run in Parallel" />

<!-- Event-Based Gateway -->
<eventBasedGateway id="waitForEvent" />

Intermediate Events

ElementDescription
Intermediate Timer CatchPauses execution for a duration (timeDuration) or until a date/time (timeDate). The server fires due timers every 30 seconds; a timeCycle is refused at deploy.
Intermediate Message CatchWaits as a worker job of type event:message:<elementId>. A correlation key (zeebe:subscription correlationKey on the <message>) is optional; the hosted API has no correlation route, so a worker completes the job, with no correlation-key matching.
Intermediate Signal CatchWaits as a worker job of type event:signal:<elementId>; there is no signal broadcast API.
Intermediate Message ThrowPasses straight through: the engine does not deliver the message to another instance or system. Use a service task and a worker to send it.
Intermediate Compensation ThrowRuns the compensation handlers of the activities that completed, in reverse order, and waits for them (activityRef targets one activity).

Boundary Events

Boundary events attach to tasks and trigger alternative paths when the attached event fires. They can be interrupting (cancel the task) or non-interrupting (run in parallel).

TypeDescription
Timer BoundaryEscalates if the task takes longer than the defined duration. Fired by the server; no worker needed.
Error BoundaryCatches a BPMN error thrown for the task or its sub-process. Always interrupting. The hosted REST API has no call for a worker to throw a BPMN error, and an error end event is read as a plain end, so on the hosted service an error boundary event does not fire today.
Message BoundaryOffered to workers as a job of type event:boundary:message:<id> while the task is active; there is no hosted correlation route.
Signal BoundaryOffered to workers as a job of type event:boundary:signal:<id> while the task is active; there is no signal broadcast API.
Compensation BoundaryDeclares how to undo the task: an <association> links it to a handler activity marked isForCompensation="true" (a normal worker job). Handlers run only for activities that completed, in reverse completion order, when the model throws compensation. A later failure does not trigger them by itself. Deploy refuses a compensation boundary without a handler (422).
<!-- Timer Boundary Event (escalate after 1 hour) -->
<boundaryEvent id="timeout" attachedToRef="reviewTask" cancelActivity="true">
  <timerEventDefinition>
    <timeDuration xsi:type="tFormalExpression">PT1H</timeDuration>
  </timerEventDefinition>
</boundaryEvent>
<sequenceFlow id="toEscalate" sourceRef="timeout" targetRef="escalate" />

<!-- Error Boundary Event -->
<boundaryEvent id="paymentFailed" attachedToRef="processPayment">
  <errorEventDefinition errorRef="paymentError" />
</boundaryEvent>
<!-- Compensation: undo "chargeCard" when the model says so -->
<serviceTask id="chargeCard" name="Charge Card">
  <extensionElements>
    <zeebe:taskDefinition type="charge-card" />
  </extensionElements>
</serviceTask>
<boundaryEvent id="undoCharge" attachedToRef="chargeCard">
  <compensateEventDefinition />
</boundaryEvent>
<serviceTask id="refundCard" name="Refund Card" isForCompensation="true">
  <extensionElements>
    <zeebe:taskDefinition type="refund-card" />
  </extensionElements>
</serviceTask>
<association id="undoChargeWith" sourceRef="undoCharge" targetRef="refundCard" />

<!-- Thrown explicitly, for example on the cancellation path -->
<intermediateThrowEvent id="compensateAll" name="Undo completed work">
  <compensateEventDefinition />
</intermediateThrowEvent>

Subprocess

A subprocess is an embedded process within the parent process. It groups tasks and has its own scope for boundary events.

An event sub-process (triggeredByEvent="true") has no incoming flow: its start event carries an error, escalation, message, signal, timer or compensation definition, and it catches what no boundary event handles. It is interrupting by default (isInterrupting="false" on its start event makes it non-interrupting). One with no typed start event is refused at deploy. On the hosted service only a timer start event fires one today, from the server's 30-second timer sweep. Error and escalation starts never fire, because nothing raises an error or an escalation there (no job call throws one, and an error end event is a plain end); message and signal starts have no correlation or broadcast call; and a process carrying a compensation start fails to start an instance today, so model the undo with compensation handlers instead. When the handler fires it is offered to workers as one job of type subProcess:<id>: the elements drawn inside an event sub-process are not run by the engine.

<subProcess id="fulfillmentSubProcess" name="Fulfillment">
  <startEvent id="subStart" />
  <serviceTask id="pickItems" name="Pick Items">
    <extensionElements>
      <zeebe:taskDefinition type="pick-items" />
    </extensionElements>
  </serviceTask>
  <serviceTask id="packItems" name="Pack Items">
    <extensionElements>
      <zeebe:taskDefinition type="pack-items" />
    </extensionElements>
  </serviceTask>
  <endEvent id="subEnd" />
  <sequenceFlow id="sf1" sourceRef="subStart" targetRef="pickItems" />
  <sequenceFlow id="sf2" sourceRef="pickItems" targetRef="packItems" />
  <sequenceFlow id="sf3" sourceRef="packItems" targetRef="subEnd" />
</subProcess>

Lanes

Lanes visually partition a pool to represent different participants, roles, or systems. They have no execution semantics - they are for modeling clarity only.

<laneSet id="laneSet1">
  <lane id="customerLane" name="Customer">
    <flowNodeRef>start</flowNodeRef>
    <flowNodeRef>submitOrder</flowNodeRef>
  </lane>
  <lane id="systemLane" name="System">
    <flowNodeRef>validateOrder</flowNodeRef>
    <flowNodeRef>processPayment</flowNodeRef>
    <flowNodeRef>end</flowNodeRef>
  </lane>
</laneSet>
Tip: Use the Priostack Designer to visually build BPMN diagrams. The designer uses bpmn-js and generates valid BPMN 2.0 XML that can be deployed directly via the API.