Request and response types
The operations the server exposes, where each runs, and the fields that matter. Names are the server's (celeriant_msg); the .NET and Rust clients wrap them in their own types. Framing and type ids are on the wire protocol page.
| Operation | Request (key fields) | Response (key fields) | Runs on | Routed by |
|---|---|---|---|---|
| Write | WriteRequest: client_id, user_id?, writes (map of AggregateKey to SingleAggregateWrite: events, allow_create, expected_version?, enforce_client_idempotency) | WriteResponse: max_aggregate_version, set only when the request wrote exactly one aggregate | leader | every key; all must land on one shard |
| Read | ReadRequest: aggregate_key, filters (ReadFilters) | ReadResponse: event_batches, next_aggregate_version? cursor | any node | aggregate key |
| Aggregate details | AggregateDetailsRequest: aggregate_key | AggregateDetailsResponse: min_/max_aggregate_version, max_event_seq, is_deleted, allow_recreate, allow_sequence_continuation, last_server_timestamp, last_client_id, last_user_id? | any node | aggregate key |
| Trim | TrimStartRequest: aggregate_key, keep_from_aggregate_version, client_id, user_id? | TrimStartResponse | leader | aggregate key |
| Delete | DeleteRequest: client_id, user_id?, deletes (map of AggregateKey to SingleAggregateDelete: allow_recreate, allow_sequence_continuation, expected_version?) | DeleteResponse | leader | every key; all must land on one shard |
| Register schema | RegisterSchemaRequest: client_id, user_id?, schema_key, schema_type (0 JSON, 1 Avro, 2 Protobuf), schema | RegisterSchemaResponse | leader | shard 0, which coordinates the other shards |
| Watch | WatchRequest: requested_latency_ms?, shard_id?, orgs?, aggregate_types?, aggregates?, operation_types? | stream of WatchResponse: events (org, type, aggregate, operation, version range) | any node | shard_id, or the filter set matching the routing rule |
| List orgs | ListOrgsRequest: shard_id, cursor? | ListOrgsResponse: orgs, next_cursor? | any node | shard_id |
| List aggregate types | ListAggregateTypesRequest: shard_id, org_id?, cursor? | ListAggregateTypesResponse: aggregate_types, next_cursor? | any node | shard_id |
| List aggregates | ListAggregatesRequest: shard_id, org_id?, aggregate_type_id?, cursor? | ListAggregatesResponse: aggregates (per-aggregate stats), next_cursor? | any node | shard_id |
? marks an optional field. AggregateKey is org_id, aggregate_type_id, aggregate_id, all u128.
Shared shape
Every request carries an optional correlation_id (u128), echoed on the response. Watch notifications carry none. Write, trim, delete and register-schema also carry client_id, the writer's identity for idempotency and the value IDENTIFY_MISMATCH checks, plus an optional user_id.
Routing
The server picks a shard per request from the cluster's --routing-rule (aggregate_id by default). A write or delete whose keys route to different shards is rejected with 9001; it is not split. See Atomic multi-aggregate writes.
Lists are per shard and paged: one request returns one page, and next_cursor continues it. The clients walk every shard for you. ListAggregatesResponse is best-effort. An aggregate whose writes span a segment rotation can show up on more than one page, so dedupe by key when paging to the end.
A watch with shard_id set watches that whole shard. Without it, the watch must carry a non-empty filter for the routing dimension (orgs when routing by org, and so on), and every value in it must route to one shard.
Leader vs any node
Write, trim, delete and register-schema run on the leader. On a follower they fail with a not-leader code (2011, 3005, 4006, 2027) whose message carries leader_address; the client pools follow it automatically. Read, details, watch and list have no leader check and run on whichever node receives them.
Clients read from the leader by default. Set RouteReadsToFollowers (.NET) or route_reads_to_followers (Rust) to send reads to followers and accept their replication lag. A follower read must not drive an optimistic-concurrency write; take that version from the leader.
Errors
Any operation can return ErrorResponse with a numeric error_code; the clients turn known codes into typed errors. See the error codes reference.