Event
Included from Basic tier
An event is one row of the append-only audit/operational spine: everything a
run, a runner, a trigger or an operator does lands here, and the triage flow
(opschain events → opschain chains triage) reads it back. JSON:API type:
event.
The v2 OpenAPI document declares this resource's schema; the resource-field coverage gate holds this page to it.
Endpoints
| Route | Serves |
|---|---|
GET /api/events | List, created_at desc then id desc by default. Default limit 10, max 1000; 206 + meta.partial_response when trimmed. |
GET /api/events/{id} | Show. |
List meta carries authorisations.update on /events and
partial_response.
The database read is bounded by the request: the server fetches limit+1
rows (the one extra detects truncation for the 206), never more than 1001 —
so a polled page costs a page-sized read, not a cap-sized one.
Attributes
The attribute object is the fixed attributes plus the event payload's own
keys spread beside them (the payload is the event's stored data document
— e.g. message, error, reason, whatever the emitter recorded). Payload
keys are filterable alongside the fixed columns — see Filters.
| Attribute | Type | Meaning / origin / null semantics |
|---|---|---|
type | string | The colon-namespaced event type — grammar below. |
username | string/null | The acting principal, recorded at write time for every principal-initiated event (run create/retry, approve/reject/continue, cancel, pause/resume, the admin and governance verbs); the stored column serialized as-is, so null on genuinely system-initiated rows — an engine roll-up carries no actor by meaning (never coerced to ""). |
system | boolean | True for system-emitted audit events (the step/run transition audits), false for user-emitted ones. |
event_node_path | string/null | The node path the event is about; null when not node-scoped. |
created_at | string | When the event was appended (ISO8601, six fractional digits). |
correlation_id | string | The chain handle; defaults to the event's own id when the row stores none. |
chain_depth | integer | Hops from the chain's origin. |
| payload keys | any | The event's data keys, spread verbatim beside the fixed attributes. Absent when the payload lacks them. |
actor | object | The audit envelope of the request that caused the event (opschain docs events, "The audit envelope"): principal_id (the acting user's id), session_id for a native session or token_id + token_kind for any other credential, client_address (resolved behind any trusted proxy), user_agent and request_id — each key present only when known, never a username or email. Absent on engine-originated events. |
The type grammar
type is colon-namespaced, three segments: a root (a severity or
family), an area (the subject domain, plural), and a verb (what
happened) — <root>:<area>:<verb>. Roots in use:
api:— run/step lifecycle facts. The chain-triage matcher names the full verb set:api:(changes|workflow_runs|steps):(create|start|success|error| system_error|abort|cancel|retry|child_complete|child_failed| pre_execution)(e.g.api:steps:success,api:changes:create). Since the root also carries the generic mutation audit (upstream'saround_action :track_event): every tracked v1 POST/PATCH/PUT/DELETE answering 2xx recordsapi:<controller>:<action>with the acting username, the request'sdata.attributes(request_body) and URL params (url_params), and the written model as the source —api:projects:create|update|destroyfor projects,api:nodes:create|update|destroyfor every other node kind, plus templates, template versions, git remotes, workflows/versions, authorisation management, properties, settings, scheduled activities (api:scheduled_workflows:*/api:scheduled_changes:*) and the run/step verbs. Lanes with their own events (run creation, artefact create, maintenance, licence, node_background_tasks create) are not doubled; the secrets endpoints emit nothing (their store_file lane is multipart); the embedded (SQLite) store has no event writer, so it records none of these. The recorded request data is masked before storage — credential-shaped attribute/parameter names (password, passphrase, secret, token, api_key, private_key, ssh_key, credential, vault_value, value_to_encrypt) store{{hidden}}, git_remotes events additionally maskuser, and URL userinfo sanitises to://hidden@— because events are customer-visible egress.audit:— attributable user actions, e.g.audit:steps:approve,audit:steps:reject,audit:steps:continue,audit:steps:cancel,audit:changes:pause,audit:changes:resume,audit:workflow_runs:pause,audit:workflow_runs:resume. These are what the run serializers fold intoapproved_by/rejected_by/paused_by.info:/warn:/error:— operational severities, e.g.info:runner:registered,info:runner:drain_changed,warn:runner:aged_out,warn:runner:fleet_drained(the dispatch plane's vocabulary —opschain docs fleet-queuelists it in full).
The CLI's --errors filter defines "error-ish" as the error:/warn:
prefixes plus the :error/:system_error/:pre_execution suffixes.
Filters
Events are the first list on the shared Ransack grammar (fail-closed: an
unknown predicate or sort is a 400, never silently dropped). Filterable
attributes: the fixed columns type, username, system (compared as
text "true"/"false"), event_node_path, created_at, id — plus any
payload field (the upstream dynamic data->> ransackers): an attribute
outside the fixed columns filters the payload key of that name as its text
rendering (booleans as "true"/"false", an absent key or json null
matching nothing), and the request_body_/url_params_ prefixes address
fields of those nested payload objects — e.g.
filter[template_version_id_eq]=…, filter[in_progress_eq]=true.
Predicates: eq, not_eq, gt, gteq, lt, lteq, cont, not_cont,
cont_any, start, end, in, not_in, present, blank, null,
true, false — e.g. filter[type_start]=audit:,
filter[created_at_gteq]=…, filter[username_in][]=…. The cont family
matches case-insensitively with LIKE metacharacters in the term taken
literally (upstream's escaped-wildcard ILIKE); start stays a byte-wise
prefix test. Grouped predicate sets combine with filter[g][][m]=and|or;
sorts with filter[sorts][]=created_at desc (sortable: created_at, id).
One ransackable scope is special-cased: filter[for_change]=<change id>
— the change's own events plus its steps' events (source_type Change or
BaseStep). A non-UUID value is a 400 invalid value for for_change: must be a change id.
The v2 EventFilter (EventService.ListEvents / WatchEvents /
GetEventStats, opschain docs api-v2) is the typed form of the
same vocabulary. Its type narrowing has three shapes: types (exact,
any-of), type_prefixes (the type starts with the prefix, any-of with
types) and type_search — the type contains every term,
case-insensitively, anywhere: agent finds warn:agent:halted and
info:agent:request alike, agent halt needs both words, and a term may
carry : (agent:halt). type_search combines with AND against the other
two. The server resolves the terms against the catalogue of event types (the
registered types plus those stored, refreshed every 30 seconds) and filters
on the exact matches through the type index, so a contains search never
scans the history; terms no type contains list nothing. The GUI's audit
history search box and opschain audit --type-search send it.
The source relationship and include=
Every event carries a source relationship whose links.source is the
source's API URL (/api/changes/{id}, /api/steps/{id},
/api/workflow_runs/{id}, /api/workflow_steps/{id}), null when the event
has no linkable source. Resource-identifier data appears only when the
request includes the source (include=source, or any source.-prefixed
path) — the upstream serializer's lazy-load posture. Workflow-step sources
carry their STI wire type (e.g. workflow_change_step); an unlinked or
unresolvable source serializes data: null. With the include, the compound
document carries the resolved change/step/run/workflow-step resources, and
dotted paths walk onward (e.g. include=source.change).
Subscriptions
Events feed the notification pipeline: a v2 NotificationService
subscription selects events with the selector grammar and delivers them
through its routes (opschain docs resources/notification; the v1
event_filters/event_subscribers families are removed). Triggers also consume events (caused_by_event_id on the runs
they fire — opschain docs triggers).
Related pages
opschain docs cli/events— the CLI view, watching and triage entry point.opschain docs fleet-queue— the runner plane's event vocabulary.opschain docs resources/change,opschain docs resources/step— where the audit events surface as attributes.