API referenceEvents API

Events API

Events in Causet are emitted by rules, not dispatched through a REST API. An emit op inside an action’s core or side_effects block appends a ledger event when the rule fires. There is no endpoint for directly inserting events into the ledger.


Event Structure

Every ledger event has the following envelope:

{
  "event_type": "ARTIST_FOLLOWED",
  "entity_id":  "user-1",
  "entity_type": "user",
  "fork_id":    "main",
  "platform_id": "my-platform",
  "application_id": "concert-app",
  "payload": {
    "user_id":   "user-1",
    "artist_id": "artist-pearl-jam"
  },
  "ts":         1719360000000,
  "cursor":     7,
  "event_id":   "evt_01j2x..."
}
FieldTypeDescription
event_typestringDSL event name (e.g. ARTIST_FOLLOWED)
entity_idstringThe entity this event belongs to
entity_typestringEntity type from the DSL state: block
fork_idstringFork the event was written to
platform_idstringPlatform identifier
application_idstringApplication identifier
payloadobjectEvent payload as defined in the DSL
tsint64Event timestamp in milliseconds since epoch
cursorint64Monotonically increasing cursor for this entity
event_idstringUnique event ID

Warning: Do not include type, ts, or entity_id as payload field names — these are reserved and will cause a compiler error (VERR_FIELD_NOT_DECLARED).


Accessing Events via gRPC

The EntityBrowserGrpcService on port 9090 provides access to the ledger event history for a specific entity.

grpcurl -plaintext \
  -d '{
    "platformId": "my-platform",
    "applicationId": "concert-app",
    "forkId": "main",
    "entityType": "user",
    "entityId": "user-1"
  }' \
  localhost:9090 \
  causet.EntityBrowserService/GetEntityEvents

This returns all ledger events for the entity in order, including full payload.


Kafka Streams

External systems integrate with Causet by consuming Kafka topics directly. This is the primary integration pattern — not REST webhooks.

causet.ledger-events.v1

The authoritative stream of all committed ledger events across all tenants and forks.

  • Format: JSON (event envelope as described above)
  • Partitioning: by entity_id
  • Ordering: per-partition (per-entity)
  • Retention: configurable (default 7 days; increase for long replay windows)

External consumers should subscribe to this topic to build their own projections, trigger webhooks, or feed data pipelines.

kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 \
  --topic causet.ledger-events.v1 \
  --from-beginning \
  --property print.key=true

causet.projection-events.v1

Internal topic consumed by the projection worker. Contains routing metadata telling the worker which projections to update for each event.

  • External consumers can subscribe to this topic but the causet.ledger-events.v1 topic is the more stable integration surface.

causet.patches.v1

Row-level patch events emitted after the projection worker successfully writes a row. Useful for downstream systems that need to react to projection changes (e.g., invalidating application-layer caches, triggering notifications).

{
  "projection_name": "user_following",
  "table":           "user_following",
  "op":              "upsert",
  "primary_key": {
    "user_id":   "user-1",
    "artist_id": "artist-pearl-jam"
  },
  "row": {
    "user_id":     "user-1",
    "artist_id":   "artist-pearl-jam",
    "followed_at": 1719360000000
  },
  "ts": 1719360000150
}

causet.projection-dlq.v1

Dead letter queue for events that could not be processed by the projection worker after all retries. Monitor this topic for failures.


External System Integration

Pattern 1 — Kafka consumer: Subscribe to causet.ledger-events.v1. Process events in your consumer. This is the most reliable integration pattern.

Pattern 2 — Webhook fan-out (Available now): A webhook delivery service sits in front of causet.ledger-events.v1 and delivers HTTP callbacks to your app. See Use Webhooks to Update Existing Flows.

Pattern 3 — Patch stream: Subscribe to causet.patches.v1 to react to projection changes without polling the query API.


Event Ordering Guarantees

  • Events for a single entity are totally ordered by cursor within a fork.
  • Kafka partitioning by entity_id preserves per-entity ordering within a partition.
  • Cross-entity ordering is not guaranteed — do not rely on global event ordering across different entities.

Emitting Events from DSL

Events are never emitted directly via API. They are always produced by emit or emit_each ops inside action rules:

actions:
  FOLLOW_ARTIST:
    ...
    side_effects:
      rules:
        - name: emit_followed
          then:
            - op: emit
              event_type: ARTIST_FOLLOWED
              payload:
                user_id:   intent.user_id
                artist_id: intent.artist_id

The emit_each op emits one event per item in a list:

- op: emit_each
  event_type: ITEM_ADDED
  for_each:   intent.items
  payload:
    item_id: item.id
    name:    item.name