Skip to main content
Lerian products emit domain events — past-tense business facts such as an account being created or a credential being issued — onto a shared streaming backbone. Any service or downstream subscriber consumes them without coupling to the producer’s internal APIs. This page describes the wire contract every event on the platform follows. The per-product pages list the concrete events each system emits and consumes.

Transport

Events travel as CloudEvents 1.0 messages in binary content mode over Kafka. Binary mode puts the CloudEvents context attributes in Kafka record headers, each prefixed with ce-, and the event body in the record value as JSON. A consumer reads routing and identity from the headers without deserializing the payload.

The envelope

Every record carries these CloudEvents headers.
HeaderPresentCarries
ce-specversionAlwaysCloudEvents spec version — 1.0.
ce-idAlwaysUnique event id (UUIDv7). Deduplicate on this value.
ce-sourceAlwaysThe producing service.
ce-typeAlwaysEvent type — studio.lerian.<resource>.<event>.
ce-timeAlwaysEmission timestamp (RFC 3339).
ce-resourcetypeAlwaysThe resource — for example account.
ce-eventtypeAlwaysThe event — for example created.
ce-schemaversionAlwaysPayload schema version.
ce-subjectWhen setThe aggregate id the event concerns.
ce-tenantidWhen setThe owning tenant; omitted for single-tenant scope.
ce-datacontenttypeWhen setBody media type — application/json.

Event type

The ce-type header names the event as studio.lerian.<resource>.<event>. An account creation in the ledger is studio.lerian.account.created. The two segments also appear on their own in ce-resourcetype and ce-eventtype, so a consumer filters on either the full type or its parts.

Topic naming

Every event lands on a Kafka topic named for the resource and event it carries, under a shared platform prefix:
lerian.streaming.<resource>.<event>
An account creation in the ledger lands on lerian.streaming.account.created; a holder creation in the CRM on lerian.streaming.holder.created. The prefix is identical across every Lerian producer, so a consumer subscribes by resource and event without needing to know which service emitted the record. The topic name carries no version suffix — the payload schema version travels in the ce-schemaversion header (see Schema versioning), so a schema change never renames a topic.

Source

ce-source identifies the producing service and is deployment-configured through the STREAMING_CLOUDEVENTS_SOURCE environment variable; it is not hard-coded in the product. It records where a record originated, for auditing and consumer-side routing. The topic name does not derive from it — topics use the shared lerian.streaming. prefix regardless of source — so a deployment is free to set any stable, descriptive source value.
ProducerDefault source
Midaz ledgerlerian.midaz.ledger
Midaz CRMlerian.midaz.crm

Subject and tenant

ce-subject carries the id of the aggregate the event is about — the account, transaction, or credential the fact concerns. ce-tenantid carries the owning tenant in multi-tenant deployments; it is omitted for single-tenant business events, so a consumer treats an absent tenant id as valid single-tenant scope rather than an error.

Schema versioning

Each event declares its own payload schema version in ce-schemaversion, independent of other events on the same source. The default is 1.0.0. A minor bump is additive and backward compatible; a major bump is a breaking change. The version lives in the header, never in the topic name, so a consumer that reads payloads as a tolerant reader — ignoring unknown fields — is unaffected by an additive change.

Delivery guarantees

Delivery is at-least-once. A consumer commits its position only after it finishes handling a record, so a crash mid-handling replays the record rather than dropping it — which means the same event can arrive more than once. Deduplicate on ce-id and keep handlers idempotent. On the producer side, durability comes from a transactional outbox. A product writes the event to its outbox in the same database transaction as the state change that produced it, so the event and the fact it reports commit or roll back together. A relay then publishes committed outbox rows to Kafka and retries through broker outages, so no committed business fact is lost before it reaches the stream.