Key Concepts
These are the core terms used throughout Aviso’s documentation and API. Read this page before Getting Started to make the commands easier to follow.
Event Type
An event type is a named category of notification, for example extreme_event, sensor_alert, or data_ready.
Every request to Aviso (notify, watch, or replay) targets exactly one event type. The server uses the event type to:
- look up the matching schema (validation rules, required fields, topic ordering),
- route messages to the correct storage stream,
- apply the correct retention and storage policy.
{ "event_type": "extreme_event", ... }
When a notification_schema is configured, Aviso is strict by default: any
event_type that is not in the schema is rejected with 400 UNKNOWN_EVENT_TYPE
on /api/v1/notification, /api/v1/watch, and /api/v1/replay. The error
body lists the configured event types so clients can self-correct.
When notification_schema is empty or absent (no schema declared at all), Aviso
falls back to generic behavior: any event type is accepted, fields are
treated as-is, and the topic is built from sorted keys. This mode is intended
for local development and quick experiments.
Operators may flip the behavior with notification_schema_strict:
notification_schema | notification_schema_strict | Effective behavior |
|---|---|---|
| non-empty | None (unset) | strict: unknown event types return 400 |
| empty / absent | None (unset) | permissive generic fallback |
| any | false | permissive generic fallback (legacy mode; a startup warning is emitted when the schema is non-empty) |
| any | true | strict: unknown event types return 400; with no schema this is deny-all |
Independent of the strict-mode knob, the event_type value that ends up on
Prometheus labels and tracing span fields is always bounded: requests whose
event_type is not in the configured schema have their observability label
collapsed to the literal "generic". In strict mode this collapsing is rarely
exercised because unknown event_types are already rejected upstream with
400 UNKNOWN_EVENT_TYPE; in permissive (legacy generic-fallback) mode it is
the main mechanism preventing unbounded label cardinality from
user-controlled input.
Identifier
An identifier is a set of key-value pairs that describe what a notification is about. Think of it as structured metadata that uniquely (or approximately) locates a piece of data.
{
"identifier": {
"region": "north",
"run_time": "1200",
"severity": "4",
"anomaly": "42.5"
}
}
Identifiers serve two purposes depending on the operation:
| Operation | Role of identifier |
|---|---|
notify | Declares the metadata of the notification being published |
watch | Acts as a filter for which notifications to receive |
replay | Acts as a filter for which historical notifications to retrieve |
In watch and replay, identifier values can be constraint objects instead of scalars
(e.g. {"gte": 5}) for numeric and enum fields. See Streaming Semantics.
Topic
A topic is the internal routing key Aviso builds from an identifier. You rarely construct topics manually; Aviso builds them for you.
Topics are dot-separated strings, for example:
extreme_event.north.1200.4.42%2E5
Each token corresponds to one identifier field, in the order defined by key_order in the schema.
The %2E is the dot in 42.5, percent-encoded so it doesn’t conflict with the topic separator.
Reserved characters (., *, >, %) in field values are percent-encoded before writing
to the backend so they do not break routing. See Topic Encoding.
Schema
A schema configures how Aviso handles a specific event type.
Schemas are defined in configuration/config.yaml under notification_schema.
A schema controls:
topic.base: the stream/prefix for this event type (e.g.diss,mars)topic.key_order: the order of identifier fields in the topic stringidentifier.*: validation rules per field (type, required, allowed values, ranges)payload.required: whether a payload is mandatory on notifystorage_policy: per-stream retention, size limits, compression (JetStream only)
Example:
notification_schema:
extreme_event:
topic:
base: "extreme_event"
key_order: ["region", "run_time", "severity", "anomaly", "polygon"]
identifier:
region:
description: "Geographic region label."
type: EnumHandler
values: ["north", "south", "east", "west"]
required: true
run_time:
type: TimeHandler
required: true
severity:
description: "Severity level from 1 to 7."
type: IntHandler
range: [1, 7]
required: true
anomaly:
type: FloatHandler
range: [0.0, 100.0]
required: false
polygon:
type: PolygonHandler
required: false
payload:
required: false
Every key listed in key_order must have a corresponding entry in identifier.
For notify, every identifier key declared in the schema must be present in the request and every value must pass the handler’s validation (an empty string, an out-of-range integer, an unparseable date, and so on are all rejected). The required flag has no effect on notify; it only changes the behavior of watch and replay. There, a missing key marked required: true returns 400, while a missing key marked required: false is treated as a wildcard. The flag never relaxes value validation; only the presence rules.
Payload
A payload is arbitrary JSON attached to a notification. Aviso treats it as opaque; it stores and replays the value exactly as sent.
Valid payload types: object, array, string, number, boolean, or null.
{ "payload": { "path": "/data/grib2/file.grib2", "size": 1048576 } }
Whether payload is required or optional is controlled per schema by payload.required.
See Payload Contract for the full input → storage → replay mapping.
Operations: Notify, Watch, Replay
Aviso exposes three operations, each on its own endpoint:
Notify: POST /api/v1/notification
Publishes a notification to the backend. The identifier must match all required schema fields exactly (no wildcards, no constraints).
Watch: POST /api/v1/watch
Opens a persistent Server-Sent Events (SSE) stream. Receives live notifications as they arrive, optionally starting from a historical point.
- Omit
from_id/from_datefor a live-only stream. - Provide one of them for historical replay first, then live.
Replay: POST /api/v1/replay
Opens a finite SSE stream of historical notifications only.
Requires exactly one of from_id or from_date.
Stream closes automatically when history is exhausted.
For end-to-end working examples of all three operations, including spatial and constraint filtering, see Practical Examples.
CloudEvents
Aviso delivers notifications to watch/replay clients as CloudEvents, a standard envelope format. Each event includes:
id: the backend sequence reference (e.g.mars@42), used for targeted delete or resume.type: the Aviso event type string, prefixed withint.ecmwf.aviso.(for exampleint.ecmwf.aviso.mars).source: the server base URL.data.identifier: the canonicalized identifier.data.payload: the notification payload (ornullif omitted).
Backend
The backend is the storage and messaging layer that Aviso delegates to. Two backends are supported:
| Backend | Use case |
|---|---|
jetstream | Production: durable, replicated, persistent history |
in_memory | Development: fast setup, no persistence |
The backend is selected via notification_backend.kind in config.
See Backends Overview.