Events — io.best.agents.events
Domain events are immutable facts published by a BEST-compliant service as the result of processing. They are the output of the service: callers observe them to retrieve command results, react, and keep read models up to date.
Normative reference: SPEC.md — Events. Canonical schema: events.json; envelope: cloudEvent.json.
Events ride the same CloudEvents 1.0 envelope as commands. Two event-specific rules:
correlationid(CloudEvents extension attribute, lowercase on the wire) is required on every event produced by processing a command — set to that command's correlation identifier (thecorrelationIdechoed byPOST /commands). Spontaneous events may omit it. This is what lets any consumer, including one that never saw the command, match events to their originating submission.dataschemais optional. With it, the event is typed — consumers fetch the schema and validate. Without it, the event is untyped — the consumer interpretsdata; the envelope (type,source,id,correlationid,time) still supports routing and correlation. Both patterns can coexist in one service; untyped suits dynamic payloads (sensor readings, log streams, forwarded third-party events).
{
"specversion": "1.0",
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"source": "https://api.example.com/negotiation",
"type": "CounterProposed",
"datacontenttype": "application/json",
"dataschema": "https://api.example.com/events/counter-proposed/1.0",
"correlationid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"time": "2025-07-01T10:30:01Z",
"data": { "salary": 100000, "startDate": "2025-09-01", "contractId": "contract-42" }
}
HTTP API
| Method | Path | Description |
|---|---|---|
| GET | /events |
Historical query — paginated log of past events, filterable by type, source, time range, correlation ID |
| GET | /events/stream |
Live stream — SSE; delivers events produced after the connection is opened |
| GET | /events/{schema}/{version} |
JSON Schema document for one event type and version (mirrors GET /commands/{schema}/{version}; 404 if unknown) |
GET /eventsandGET /events/streamare complementary, not alternatives. History first, then open the stream:GET /events?correlationId=abc123 → what has already happened GET /events/stream?correlationId=abc123 → what happens next
No replay guarantee.
GET /eventsreturns whatever the server currently exposes — a full log, a recent window, or a mapped view of domain records. Clients cannot assume completeness, ordering, or replay fidelity. For reliable point-in-time delivery, use a push channel.
Query parameters (GET /events)
| Parameter | Description |
|---|---|
type |
Filter by envelope type (PascalCase), across all interactions |
correlationId |
Only events whose correlationid envelope attribute matches |
source |
Filter by publishing service |
from / to |
ISO 8601 time-range bounds (inclusive) |
limit |
Max results; servers may apply a lower ceiling |
after |
Opaque pagination cursor — pass the previous response's nextCursor, preserving all other parameters; absent nextCursor means last page |
SSE stream (GET /events/stream)
Request with Accept: text/event-stream plus credentials; optional filters correlationId, type, source. Each event arrives as an SSE data field with the envelope JSON; the envelope id is echoed as the SSE event id. On reconnect, clients send Last-Event-ID and the server replays anything produced after it. Servers should send : keepalive comments and may close after inactivity or a terminal event; clients must handle reconnection — the stream is not lossless.
Event catalogue
GET /events may also serve catalogue entries mirroring the command catalogue: schema (kebab-case), version, optional dataschema (omitted for untyped events), description — the primary documentation for untyped events.
Push channels
Polling is the universal fallback. The events capability declares its push channels in the manifest's push block:
"push": { "sse": true, "mcp": true }
| Caller | Channel |
|---|---|
| Browser app, CLI, local agent | SSE — no public endpoint required |
| LLM client with an active MCP session | MCP push — server-to-client notifications, matched by correlation identifier; declared with "push": true on the mcp block |
| Anything else | Polling GET /events — always available |
Mapping domain records to BEST events
Implementations without a native event store may map domain records (audit entries, trade history, sensor readings) to the BEST event shape at query time. The protocol only requires that responses conform to the events schema — it never prescribes internal storage.