Skip to main content

Events

Record and query operational events.

An event's externalId is a correlation key, not an identity

This is the opposite of what it means on a resource, and it is deliberate. An event's external id is the source system's key for the subject the event is about — an order, a permit, a batch — so many events share one. "Everything that happened to PO-4500171" is one indexed lookup, and that is what makes the log an audit trail.

No uniqueness is enforced, and none ever will be. Per-event identity is the event id below. Naming policies do not apply to events either; only the charset floor does, so 21-PT-1234 is accepted on an event even when a snake_case policy is rejecting it on resources. The two contracts →

Create

Every event must carry an event time — the moment it occurred at the source (sensor, PLC, upstream system). The SDK deliberately does not default it to "now": an event without it is rejected rather than silently mis-timestamped.

EventModel event = new EventModel();
event.setExternalId("door_open");
event.setType("alarm");
event.setEventTime(ZonedDateTime.now()); // required: when the event occurred

client.events().create(List.of(event));
Event ids are time-ordered UUID v7

The ingestion paths stamp every event that has no id with a UUID v7 before sending — create in the Python and Rust clients, ingest(...) in Java (a plain Java create sends events as-is and lets the server assign ids). The server honors a client-supplied id, which is what makes retries idempotent: the events table is a ReplacingMergeTree ordered by id, so re-sending the same event (for example after a buffered outage) collapses to one row instead of duplicating. If you set the id yourself, use a time-ordered UUID v7 — a random v4 scatters writes across that sort key and hurts insert/query performance. The created event (with its id) is returned from create.

Query

EventRetreiver retriever = new EventRetreiver();
retriever.setLimit(50);
retriever.getFilter().setType("alarm");
DataWrapper<EventModel> events = client.events().filter(retriever);

High-throughput ingestion

ingest chunks, parallelises and retries events the same way as datapoints, returning the same IngestResult tuned with the same IngestOptions:

IngestResult result = client.events().ingest(events,
IngestOptions.builder().batchSize(1_000).parallelism(8).build());

Delete

client.events().delete(List.of(IdCollection.createFromExternalId("door_open")));