Business Events

Enterprise Edition only

Business Events were introduced in EximeeBPMS 1.2.16-ee (Enterprise Edition). As of this writing, this feature has not shipped in any Community Edition release. The set of covered entities was substantially expanded, and the default event type prefix changed, in 1.3.1-ee — see the notes on the prefix configuration property below if you’re upgrading from an earlier release.

Business Events let the process engine publish a stream of domain-level occurrences — a task was completed, a variable changed, a process instance ended — to systems outside the engine, without coupling the engine’s own transaction to the availability of those systems.

For the exact fields carried by each event type’s payload, see Business Event Field Reference.

How It Works

Business Events use the transactional outbox pattern:

  1. When an event-worthy change happens (e.g., a task is completed), the engine writes a row describing it to the ACT_RU_BUS_EVT_OBX table, in the same database transaction as the change itself.
  2. A background dispatcher periodically reads batches of undelivered rows from the outbox and hands them to the configured publisher.
  3. Once a publisher confirms delivery, the corresponding outbox rows are marked delivered; a separate cleanup job removes delivered rows past their retention period.

Because the outbox write is part of the same transaction as the business change, an event is never recorded for a change that didn’t commit, and a committed change never silently fails to produce its event — delivery to the publisher is a separate, retried concern. This gives at-least-once delivery to downstream systems: consumers should treat delivery as idempotent (the metadata.uuid field described below can be used for deduplication).

Event Envelope

What a publisher (e.g. the kafka publisher, or a custom BusinessEventPublisher) actually receives is an Event envelope wrapping the business event, not the business event object directly:

{
  "metadata": {
    "timestamp": "2026-07-29T10:15:23.456+00:00",
    "uuid": "1c1a9e2e-2a34-4b7d-9f0a-6e3d3a2b9c11",
    "type": "bpms:task-instance:complete",
    "version": "1.0",
    "origin": "bpms",
    "correlationId": null,
    "processInstanceId": "3f2c...",
    "processDefinitionKey": "invoice-approval",
    "noProcessContext": false
  },
  "payload": "{\"id\":\"...\",\"processInstanceId\":\"3f2c...\", ... }"
}
FieldTypeDescription
metadata.timestampInstantWhen the outbox row was written (i.e. when the underlying business change committed), not when it was dispatched.
metadata.uuidStringA fresh random UUID generated at dispatch time. Not the same as the business event's own id field — use this for de-duplicating retried deliveries of the same dispatch attempt.
metadata.typeStringThe fully-qualified business event type, in the form <prefix>:<entity>:<event> — see Business Event Types below. Mirrors the businessEventType field inside payload.
metadata.versionStringEnvelope schema version. Currently always "1.0".
metadata.originStringAlways the literal "bpms". Unlike metadata.type, this is not affected by the configured prefix — don't use it to distinguish between engines that are configured with different prefixes.
metadata.correlationIdStringReserved for future use. Currently always null.
metadata.processInstanceIdStringRoot process instance id if the event has a process context; otherwise the literal "no-process-context" (see noProcessContext).
metadata.processDefinitionKeyStringProcess definition key if the event has a process context; otherwise "no-process-context".
metadata.noProcessContextbooleantrue when the underlying change has no associated process instance (e.g. a job or user operation log entry that isn't tied to a running instance).
payloadStringThe business event itself, serialized to a JSON string (not a nested JSON object) using Gson. Its own field names match the Java entity's field names exactly — one-to-one, no getter/property renaming. Deserialize this string separately to access the fields documented in Business Event Field Reference.

Business Event Types

Each business event carries its fully-qualified type in the businessEventType field of its payload (and in metadata.type of the envelope), in the form <prefix>:<entity>:<event>. The default prefix is bpms and is configurable; examples below use the default.

For the exact payload fields behind each row, follow the links to the Business Event Field Reference.

Process & Task Lifecycle

Fired whenEvent type
Process instance startedbpms:process-instance:start
Process instance updatedbpms:process-instance-update:update
Process instance endedbpms:process-instance:end
Process instance migrated to another process definition versionbpms:process-instance:migrate
Activity instance startedbpms:activity-instance:start
Activity instance updatedbpms:activity-instance:update
Activity instance migratedbpms:activity-instance:migrate
Activity instance endedbpms:activity-instance:end
Task instance createdbpms:task-instance:create
Task instance updatedbpms:task-instance:update
Task instance migratedbpms:task-instance:migrate
Task instance completedbpms:task-instance:complete
Task instance deletedbpms:task-instance:delete
Fired whenEvent type
Variable createdbpms:variable-instance:create
Variable updatedbpms:variable-instance:update
Variable migratedbpms:variable-instance:migrate
Variable deletedbpms:variable-instance:delete
Identity link added (candidate/assignee/owner)bpms:identity-link-add:add-identity-link
Identity link deletedbpms:identity-link-delete:delete-identity-link

Upgrading from 1.3.1-ee

In 1.3.1-ee, Variable business events used inconsistent past-tense type names — variable-instance:created, variable-instance:updated, variable-instance:deleted — instead of the imperative-style names every other entity uses. As of 1.3.2-ee, these are corrected to create/update/delete as shown above (migrate was already correctly named). If you built downstream consumers against the 1.3.1-ee strings, update them — the old strings are no longer published.

Jobs, Batches & External Tasks

Fired whenEvent type
Job createdbpms:job:create
Job execution failedbpms:job:fail
Job executed successfullybpms:job:success
Job deletedbpms:job:delete
Batch startedbpms:batch:start
Batch execution progress updatedbpms:batch:update
Batch endedbpms:batch:end
External task createdbpms:external-task:create
External task execution failedbpms:external-task:fail
External task executed successfullybpms:external-task:success
External task deletedbpms:external-task:delete

Incidents & Decisions

Fired whenEvent type
Incident createdbpms:incident:create
Incident migratedbpms:incident:migrate
Incident resolvedbpms:incident:resolve
Incident updatedbpms:incident:update
Incident deletedbpms:incident:delete
DMN decision evaluatedbpms:decision:evaluate

Forms & Audit Trail

Fired whenEvent type
Form property submitted/updated via a task or start formbpms:form-property:form-property-update
User operation log entry created (one event per changed property)bpms:user-operation-log:create
Script violation detected — Script Guard records a violation (AUDIT or ENFORCE mode)bpms:script-violation:create

Configuration

Business Events are configured under the eximeebpms.bpm.business-events prefix and are disabled by default:

eximeebpms:
  bpm:
    business-events:
      enabled: true
      publisher: kafka
      prefix: bpms
      business-event-dispatch-interval-ms: 5000
      business-event-dispatcher-batch-size: 100
      business-event-outbox-retention-ms: 604800000   # 7 days
      business-event-outbox-cleanup-interval-ms: 3600000  # 1 hour
      publisher-properties:
        kafka.bootstrap-servers: "kafka-1:9092,kafka-2:9092"
        kafka.topic: "eximeebpms.business-events"
PropertyDefaultDescription
enabledfalseMaster switch for the whole feature. When disabled, no outbox rows are written and the dispatcher does not run.
publishernoopSymbolic name of the publisher to dispatch events to.
prefixbpmsPrefix prepended to every business event's fully-qualified type, i.e. the <prefix> in <prefix>:<entity>:<event>. Added in 1.3.1-ee. Does not affect the envelope's metadata.origin field, which is always "bpms" — see Event Envelope.
business-event-dispatch-interval-ms5000How often the dispatcher polls the outbox for undelivered events.
business-event-dispatcher-batch-size100Maximum number of outbox rows read and handed to the publisher per dispatch cycle.
business-event-outbox-retention-ms604800000 (7 days)How long delivered outbox rows are kept before cleanup removes them.
business-event-outbox-cleanup-interval-ms3600000 (1 hour)How often the cleanup job runs.
publisher-propertiesemptyPublisher-specific properties (see below), passed through to BusinessEventPublisher.init(Map).

Upgrading from a release before 1.3.1-ee

Releases before 1.3.1-ee published events with the hardcoded prefix camunda7 (e.g. camunda7:task-instance:complete). Starting with 1.3.1-ee, the default prefix is bpms. If downstream consumers (SIEM rules, stream processors, dashboards) match on the literal type string, either update them to the bpms: prefix or set prefix: camunda7 explicitly to preserve the previous behavior during migration.

Built-in Publishers

noop (default)

Writes to the outbox but never dispatches anywhere. Useful for exercising the outbox and cleanup mechanics without wiring an external system.

kafka

Publishes events to an Apache Kafka topic. Enable with publisher: kafka and configure under publisher-properties:

PropertyRequiredDescription
kafka.bootstrap-serversyesComma-separated list of Kafka bootstrap servers.
kafka.topicyesKafka topic events are published to.
kafka.client-idnoKafka client id.
kafka.send-timeout-msnoTimeout waiting for broker acknowledgement. Default 30000.
kafka.client.*noPassed through verbatim to the underlying Kafka producer, with the kafka.client. prefix stripped (e.g. kafka.client.acks=all becomes producer property acks=all).

Writing a Custom Publisher

To deliver events somewhere other than Kafka (a webhook, a message broker, a SIEM ingestion endpoint), implement the BusinessEventPublisher SPI:

package org.eximeebpms.bpm.commons.eventbus;

public interface BusinessEventPublisher extends AutoCloseable {

  String getName();

  default void init(Map<String, String> properties) {
  }

  BusinessEventPublishResult publish(Event event);

  @Override
  default void close() {
  }
}

Register the implementation so it’s discoverable under its getName() value, then set publisher: <name> in configuration. init(Map<String, String>) receives whatever is configured under publisher-properties for that publisher name.

Script Guard / SIEM Integration

As of 1.2.19-ee, Script Guard violations are published as business events (bpms:script-violation:create by default) through this same mechanism. This means routing Script Guard violations to a SIEM is a matter of enabling Business Events and pointing the configured publisher at your SIEM ingestion endpoint (via the Kafka publisher, or a custom BusinessEventPublisher implementation) — no separate integration is required. The same applies to the user operation log events introduced in 1.3.1-ee, which give a SIEM a real-time feed of administrative actions (task assignment/suspension, batch/job/deployment operations) in addition to the periodic ACT_HI_OP_LOG table.

Querying the Outbox

The engine exposes a query API over the outbox via BusinessEventService:

processEngine.getBusinessEventService()
    .createBusinessEventOutboxQuery()
    .processInstanceId(processInstanceId)
    .eventType("bpms:script-violation:create")
    .list();

This is primarily useful for diagnostics and for verifying delivery independently of the configured publisher.

On this page