Events

Event Bus

The event bus provides topic-based pub/sub messaging across the platform, backed by NATS. Learn about topic routing, subscriptions, and event delivery.

The event bus is the platform's distributed messaging system. It routes events from producers to consumers using a topic-based pub/sub model, backed by NATS.

Topics

Events are routed through topics — hierarchical addresses that describe the event:

events.{orgId}.{source}.{resource}.{event}.{resourceId}[.{filterKey}.{filterValue}...]
SegmentDescriptionExample
orgIdOrganization scopeorg_abc123
sourceThe originating serviceconversations, flows, apps
resourceThe resource typeconversation, flow, task
eventWhat happenedcreated, message_posted, completed
resourceIdThe specific resourceconv_xyz, * (wildcard)
filterKey.filterValueOptional additional filtersparticipant.part_789

Topic examples

TopicWhat it matches
events.org_123.conversations.conversation.message_posted.*All messages in org_123
events.org_123.flows.flow.run.*All flow runs in org_123
events.*.apps.app.event_received.app_456Webhook events for app_456 across all orgs
events.org_123.conversations.conversation.message_posted.*.participant.part_789Messages filtered by participant

Wildcards

The * wildcard matches any single segment. This enables flexible subscriptions:

  • Subscribe to all events of a type across all resources
  • Subscribe to all events for a specific resource regardless of event type
  • Subscribe across all organizations (for system-level handlers)

Publishing events

Services publish events by specifying the event name and payload:

Publish(context, "conversation.message_posted", Event{
    ResourceID: conversationId,
    Payload:    messageData,
})

The event bus constructs the full topic from the event context (organization, source service, resource type) and routes it to matching subscribers.

Subscribing to events

Subscribers register handlers for specific topic patterns:

Subscribe(orgId, "conversation.message_posted", handler, filters, localOnly)

Parameters:

ParameterDescription
orgIdOrganization to scope the subscription (or * for all)
eventNameThe event pattern to match
handlerThe function to call when a matching event arrives
filtersOptional additional filter criteria
localOnlyIf true, only matches events on the same instance (used for instance-affine handlers like conversation flow triggers)

Persistent subscriptions

Event subscriptions configured through the API (for example, webhook event subscriptions for apps) are persisted in the database. When the platform restarts, these subscriptions are automatically restored.

Local-only subscriptions

Some handlers need to run only on the instance that owns the relevant state. For example, flow engine handlers that manage active flow runs subscribe with localOnly: true to ensure messages for a running flow are handled by the instance that owns the flow execution.

Event delivery

Events are dispatched asynchronously through a bounded worker pool:

  • Events are placed in a queue
  • A pool of workers processes events concurrently
  • Each worker evaluates the event against registered handlers and dispatches matches

This architecture ensures that event processing doesn't block the publishing service and handles bursts gracefully.

Persistence

The event bus supports two persistence modes:

  • Ephemeral — events are delivered to current subscribers only. If no subscriber is listening, the event is lost.
  • Persistent (via NATS JetStream) — events are stored and can be replayed. Used for critical events like webhook deliveries that must not be lost.