Developer Docs · 05

The Event Bus

Plugins communicate through a typed publish/subscribe bus. Domain events emitted by core are bridged onto the same bus automatically.

Why a bus

The bus decouples producers from consumers. A plugin emits an event (“payment captured”, “coupon redeemed”) without knowing who listens; any number of plugins subscribe without the emitter changing. Core domain events are forwarded onto the same EventBus, so plugins get one consistent stream.

Subscribing

Override register_event_handlers on your plugin class. It runs once when the plugin is enabled:

class MyPlugin(BasePlugin):
    def register_event_handlers(self, bus):
        bus.subscribe("payment.captured", self._on_paid)

    def _on_paid(self, event):
        user_id = event.data["user_id"]
        # …react: grant access, send mail, credit tokens…

Publishing

class MyService:
    def __init__(self, bus):
        self._bus = bus

    def do_thing(self, user_id):
        # …work…
        self._bus.publish("my.thing_done",
                          {"user_id": user_id, "amount": 10})
Event payloads must never broadcast another user's personal data. Personal-data entities are never put on the bus — see RBAC & access levels for the GDPR rules.

Subscribe-all (relays)

Infrastructure that needs every event — e.g. the outbound webhook relay — uses bus.subscribe_all(handler) and filters downstream. That is how a generic, plugin-agnostic webhook system delivers any plugin's events without importing the plugin.