Learn · Room model

Events

Event payloads, server-assigned fields, ordering, and source references.

An event is an immutable, durable fact in a room. It answers “what happened?” so another client can interpret it now or after reconnecting. A committed message, structured observation, or completed task can be an event.

Define a fact consumers can understand

TypeScript
// room is an authorized RoomClient; chat has been provisioned.
const event = await room.publish({
  clientEventId: crypto.randomUUID(),
  channelId: "chat",
  type: "text.message.committed",
  correlationId: "support-case-42",
  payload: {text: "Can you check the shipment?"},
});
console.log(event.id, event.seq, event.actor_id);

Use a stable type name and an explicit payload contract. TypeScript generics describe expected data to the compiler; they do not validate incoming JSON. Consumers should validate the payload before applying it. When a contract evolves, preserve how older facts are interpreted or give the new shape a distinct version/type.

Know which fields come from whom

Field Owner Purpose
clientEventId Publisher Identity of one logical publication across retries
type, payload, channelId Publisher Meaning, data, and topic
causationId Publisher Event that caused this fact
correlationId Publisher Grouping for a product workflow
visibility Publisher, enforced by RMC Intended recipients
id, seq, actor_id, occurrence time RMC Stored identity, room order, and authenticated provenance

Causation links a derived fact to its input; correlation groups facts in a workflow. See the SDK reference for the input and wire field conventions.

Follow every path that creates an event

Every durable event crosses the same append boundary, but it can arrive there in several ways.

Source What initiates it Typical events
Participant publication A client calls room.publish(...) or channel.publish(...) text.message.committed, application-defined facts
Resource mutation RMC changes durable state in the same SQLite transaction state.patched, artifact, delegation, and conversation-turn events
Room agent or adapter Trusted host code reacts to an event or finishes work Agent outputs, delegation progress and results, tool traces
Native provider integration A provider callback is validated and normalized by an adapter Media lifecycle and voice.* events

The TypeScript SDK currently uses HTTP POST /events for room.publish(...); the version 2 WebSocket protocol also defines a publish operation for other clients. Both enter a participant-bound RoomSession. That session derives actor_id from the authenticated participant, reloads current grants after the publication reaches the room command queue, and rejects a caller that cannot publish to the selected channel or event type.

Inside the queue, SQLite checks client_event_id, reads the room's current last_seq, assigns seq = last_seq + 1, creates an event ID and timestamp, inserts the event, and advances the room sequence in one transaction. The runtime wakes subscriptions only after that command succeeds. Subscribers then read the committed log; the notification itself is not the event payload and is not the source of truth.

Internal resource operations can produce an event without going through the public publication body. For example, a conversation-turn update writes the current turn projection and appends conversation.turn.updated or conversation.turn.committed in the same transaction. A provider callback is not durable merely because an adapter received it: the adapter must convert it to a storage-safe RMC event and pass it to the runtime.

RoomSession publication, the per-room command path, and SQLite append show the complete boundary. OpenAI Realtime normalization is a concrete provider-derived example.

Read from the committed history

The client publishes with a stable client event ID. RMC rechecks current authority and idempotency, then SQLite commits the ordered event. Subscription delivery reads authorized committed history.
A commit precedes delivery. External application effects remain a separate boundary.Open SVG ↗Excalidraw source ↓

A publication becomes durable before readers are notified. Live delivery and replay read the same log. Sequence numbers order this room's facts, including events from different channels; there is no cross-room total order.

An accepted retry returns the original event. It does not modify that event's payload. Publish a new fact for a correction or use versioned state for a current value. The publisher page explains retry identity and uncertain HTTP responses.

Persist outcomes that remain useful

Typing, audio meters, and transient presence belong in LiveKit or local UI state. Continuous media stays on its native transport. Keep the journal for facts a later consumer needs.

Read EventEnvelope, publication validation, and publication tests. Continue with subscriptions to consume the result.

For voice, continue with the Realtime turn walkthrough to see how ephemeral provider traffic becomes selected durable events.

Search the documentation

Type to search all guides.

Diagram

100%Open original ↗