Skip to main content

EventStore API

The EventStore service owns event operations:

  • SaveEvents
  • GetEvents
  • CatchUpSubscribeToEvents
  • Ping
  • CreateIndex
  • DropIndex

All examples use the default Basic auth header:

AUTH='Authorization: Basic YWRtaW46Y2hhbmdlaXQ='

Data model

Events have four caller-supplied fields:

FieldDescription
event_idStable event identifier. Use this for idempotency and deduplication.
event_typeEvent type name, for example OrderPlaced.
dataJSON object encoded as a string. Criteria queries match this JSON object.
metadataJSON object encoded as a string. Use for request source, tracing, or non-domain metadata.

Orisun also stores a durable position and date_created on committed events.

note

SaveEvents adds eventType to the stored event data from event_type, so criteria and indexes can use the eventType JSON key.

SaveEvents

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/SaveEvents <<EOF
{
"boundary": "orders",
"query": {
"expected_position": {
"commit_position": -1,
"prepare_position": -1
}
},
"events": [
{
"event_id": "order-001",
"event_type": "OrderPlaced",
"data": "{\"customer_id\":\"c-1\",\"amount\":45}",
"metadata": "{\"source\":\"checkout\"}"
}
]
}
EOF

Batches are atomic. Events in one batch share the same commit position and receive increasing prepare positions.

Save with a consistency subset

Use query.subsetQuery to enforce Command Context Consistency for a specific event subset:

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/SaveEvents <<EOF
{
"boundary": "orders",
"query": {
"expected_position": {
"commit_position": 12,
"prepare_position": 8
},
"subsetQuery": {
"criteria": [
{
"tags": [
{"key": "customer_id", "value": "c-1"}
]
}
]
}
},
"events": [
{
"event_id": "order-002",
"event_type": "OrderConfirmed",
"data": "{\"customer_id\":\"c-1\",\"amount\":45}",
"metadata": "{}"
}
]
}
EOF

If the subset changed after the expected position, Orisun returns ALREADY_EXISTS.

GetEvents

Read from the beginning:

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/GetEvents <<EOF
{
"boundary": "orders",
"count": 100,
"direction": "ASC"
}
EOF

Read by criteria:

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/GetEvents <<EOF
{
"boundary": "orders",
"query": {
"criteria": [
{
"tags": [
{"key": "customer_id", "value": "c-1"}
]
}
]
},
"count": 100,
"direction": "ASC"
}
EOF

Page from a position:

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/GetEvents <<EOF
{
"boundary": "orders",
"from_position": {
"commit_position": 1000,
"prepare_position": 42
},
"count": 100,
"direction": "ASC"
}
EOF

GetEvents returns matching events with their committed position and creation time:

{
"events": [
{
"event_id": "order-001",
"event_type": "OrderPlaced",
"data": "{\"customer_id\":\"c-1\",\"amount\":45}",
"metadata": "{\"source\":\"checkout\"}",
"position": {"commit_position": 1, "prepare_position": 0},
"date_created": "2026-05-30T12:00:00Z"
}
]
}

Event adds position and date_created to the fields supplied at write time. CatchUpSubscribeToEvents delivers the same event shape.

Paging through a boundary

GetEvents returns one bounded page (count, server-capped at 10000). To walk the whole log or a criteria set, page forward:

  1. First call uses from_position {-1, -1} to start at the beginning.
  2. Process the page, then take the position of the last event.
  3. Pass it as from_position on the next call.
  4. Stop when a page returns fewer events than count.

Keep the consumer idempotent and deduplicate by event_id rather than assuming exactly-once paging. The position model behind from_position and direction is described in Positions and Ordering.

CatchUpSubscribeToEvents

Catch-up subscriptions replay stored events, then switch to live JetStream delivery.

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/CatchUpSubscribeToEvents <<EOF
{
"subscriber_name": "order-projector",
"boundary": "orders",
"after_position": {
"commit_position": -1,
"prepare_position": -1
}
}
EOF

Filtered subscription:

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/CatchUpSubscribeToEvents <<EOF
{
"subscriber_name": "placed-orders",
"boundary": "orders",
"after_position": {
"commit_position": -1,
"prepare_position": -1
},
"query": {
"criteria": [
{
"tags": [
{"key": "eventType", "value": "OrderPlaced"}
]
}
]
}
}
EOF

Ping

Ping is an authenticated liveness check that takes no arguments:

grpcurl -H "$AUTH" -d '{}' localhost:5005 orisun.EventStore/Ping

CreateIndex

grpcurl -H "$AUTH" -d @ localhost:5005 orisun.EventStore/CreateIndex <<EOF
{
"boundary": "orders",
"name": "customer_id",
"fields": [
{"json_key": "customer_id", "value_type": "TEXT"}
]
}
EOF

value_type is TEXT, NUMERIC, BOOLEAN, or TIMESTAMPTZ. Add conditions for a partial index. Each condition operator must be one of =, >, <, >=, or <=. See Indexing for composite and partial index examples.

DropIndex

grpcurl -H "$AUTH" \
-d '{"boundary":"orders","name":"customer_id"}' \
localhost:5005 orisun.EventStore/DropIndex

Proto source

The EventStore protobuf source lives at proto/eventstore.proto.

Common status codes

StatusMeaning
INVALID_ARGUMENTThe request is malformed, uses invalid JSON, or references invalid index fields.
UNAUTHENTICATEDMissing or invalid credentials.
PERMISSION_DENIEDAuthenticated user does not have a required role.
ALREADY_EXISTSOptimistic consistency conflict during SaveEvents; re-query and retry if still valid.
INTERNALStorage, publishing, or unexpected server failure.