Skip to main content
Every entity change is delivered in real time to connected clients. The mechanism differs for users (frontend) and services (background processors).

WebSocket protocol

All real-time communication happens over WebSocket using a JSON protocol with a type discriminator field.

Events (Server → Client)

Commands (Client → Server)

User data flow

1

Entity committed

A change is persisted and a checkpoint is created.
2

Broadcast

The change is broadcast to all API nodes via pub/sub.
3

Subscription evaluation

Each node evaluates the change against every connected user’s subscriptions. If the entity matches the query, an entity change event is sent. If the entity was being watched but no longer matches, a refresh event is sent telling the client to refetch its list.
User changes are fire-and-forget. Users don’t acknowledge receipt. If a user is offline when a change happens, they’ll get the current state when they reconnect and subscribe.

Subscription refresh

When an entity leaves a user’s subscription (e.g., an account’s workstream changes from “DenialManagement” to “None” while a user is viewing the denial queue), a refresh event is sent. This tells the client: “an entity you were watching no longer matches your query — refetch your list.”

Service data flow

1

Entity committed

A change is persisted and a checkpoint is created.
2

Query matching

The change is evaluated against all background service queries.
3

Enqueue

Matching changes are enqueued to the service’s dedicated message queue.
4

Delivery

The service receives the change event via its WebSocket connection.
5

Acknowledge

The service processes the change and sends an acknowledgment (success or failure).
Key difference from users:
  • Durable — messages persist even if the service is offline
  • Acknowledged — services must confirm processing
  • Retried — unacknowledged messages are re-delivered after a timeout

Multi-node architecture

Our API runs across multiple nodes behind a load balancer. The challenge: a change committed on Node A must reach a user connected to Node B. Changes are broadcast to all nodes via a pub/sub bus. Each node evaluates the change against its locally connected users’ subscriptions and delivers matching events. This ensures every user gets real-time updates regardless of which node they’re connected to.

Change event payload

An entity change event includes:
Both the previous and current state are included, so clients can compute what changed without an additional API call.