Skip to content
Ironflow is pre-1.0: APIs can change between releases. Pin a version. What is ready →

ironflow event

Explain event routing, manage event schemas, test upcasters, and redact events.

Terminal window
ironflow event <subcommand> [flags]

events is an alias for event.

Explain current routing eligibility without emitting an event. Supply exactly one stored event ID or proposed event name.

Terminal window
ironflow events explain --event-id evt_123 --json
ironflow events explain --event order.created --data '{"orderId":"123"}' --json
ironflow events explain --event order.created --data-file event.json --version 2
FlagTypeDefaultDescription
--event-idstringStored event ID in the selected environment
--eventstringProposed event name
--datastring{}Proposed event JSON payload
--data-filestringJSON file, or - for stdin
--versionint320Proposed schema version; 0 means 1
--idempotency-keystringUse the original event if this key already exists
--jsonboolfalsePrint the canonical response with snake_case keys
--server, -sstringServer URL override

Proposed event flags cannot accompany --event-id. --data and --data-file are mutually exclusive. The command uses the configured credentials and environment, as other event commands do.

The result contains event_id, event_name, and a functions array. Each entry has function_id, name, and one reason.

Without --json, the command prints a table with the columns FUNCTION ID, NAME and REASON.

ReasonMeaning
matchedAt least one current trigger matches
no_triggerNo event-name trigger matches, including invoke-target restrictions
filter_falseA matching trigger’s CEL filter returned false
cel_errorA matching trigger’s CEL filter could not compile or evaluate
schema_rejectThe current reject-mode schema policy would refuse the proposed event
duplicateA run already exists for this function, or the proposed idempotency retry resolves to a processed event
redacted_or_encryptedA matching trigger needs an unavailable payload for CEL evaluation

A successful trigger wins over errors or false results from other triggers. Otherwise CEL errors take precedence over false, then no trigger. Event-name-only triggers and successful CEL expressions retain live matching behavior for unavailable payloads. Structural redaction markers and encryption envelopes are recognized; arbitrary user field names are not treated as redaction.

Stored events and idempotency hits use the original payload and skip ingest schema validation, as dispatch resume does. Existing runs take precedence; an unprocessed event can still be eligible for missing runs. Proposed idempotency retries of processed events return duplicate, because live ingest does not dispatch them again. Stored-ID requests assess current trigger eligibility instead. Schema warn mode permits matching. A registry outage returns an error rather than a schema-rejection reason.

These results describe current eligibility, not historical routing or a guarantee of dispatch. Capacity, debounce, dispatch failures, and concurrent changes can affect execution. The operation creates no event, run, debounce slot, or trace anchor and does not wake waiting workflows.

Requires events:subscribe for the event and functions:list. Only functions the caller can read appear. Cross-environment IDs and definition-history events return not-found. Python exposes rpc.events.explain_match. Go and JavaScript convenience wrappers are not yet available.

Register a JSON schema for an event type at a specific version.

Terminal window
ironflow event schema register <event-name> [flags]

Arguments:

ArgumentRequiredDescription
event-nameYesThe event name (e.g., order.created)

Flags:

FlagShortTypeDefaultDescription
--versionintSchema version (required)
--filestringPath to JSON schema file
--schemastringInline JSON schema string
--descriptionstringSchema description
--reasonstringReason for replacing the schema definition
--server-sstringServer URL override

One of --file or --schema is required. Cannot use both.

Examples:

Terminal window
ironflow event schema register order.created --version 1 --file schema.json
ironflow event schema register order.created --version 1 --schema '{"type":"object"}'
ironflow event schema register order.created --version 2 --file schema-v2.json --description "Added address field"

The command prints Schema <event-name> (v<version>): created or updated.

The schema must be a JSON Schema the server can compile (draft 2020-12); a malformed document is rejected. Re-registering an existing (event name, version) overwrites it and reports updated rather than created.

The created/updated distinction is advisory. It is read before the upsert rather than derived from it, so two registrations racing on the same (event name, version) can both report created. The write itself is still correct — last one wins — and this is a display label on a command a human runs, not a value to branch on.

Registering a schema does not by itself enforce it. See IRONFLOW_EVENT_SCHEMA_ENFORCEMENT, which is off by default. --reason <text> records an optional explanation with the archived old definition. It does not create a revision when registration leaves the definition unchanged.

List registered event schemas.

Terminal window
ironflow event schema list [flags]

Flags:

FlagShortTypeDefaultDescription
--eventstringFilter by event name
--limitint100Maximum number of schemas to return
--jsonboolfalseOutput as JSON
--server-sstringServer URL override

Output:

EVENT VERSION DESCRIPTION REGISTERED
order.created 1 Order created event 2025-01-15 12:00:05
order.created 2 Added address field 2025-01-20 09:30:00

Examples:

Terminal window
ironflow event schema list
ironflow event schema list --event order.created
ironflow event schema list --json

Get detailed information about a registered event schema.

Terminal window
ironflow event schema get <event-name> [flags]

Arguments:

ArgumentRequiredDescription
event-nameYesThe event name to look up

Flags:

FlagShortTypeDefaultDescription
--versionint0Schema version (0 = latest)
--jsonboolfalseOutput as JSON
--server-sstringServer URL override

Output:

Event: order.created
Version: 2
Description: Added address field
Registered: 2025-01-20 09:30:00
Schema:
{"type":"object","properties":{"id":{"type":"string"},"address":{"type":"object"}}}

Examples:

Terminal window
ironflow event schema get order.created
ironflow event schema get order.created --version 2
ironflow event schema get order.created --json

Delete a registered event schema.

Terminal window
ironflow event schema delete <event-name> [flags]

Arguments:

ArgumentRequiredDescription
event-nameYesThe event name to delete

Flags:

FlagShortTypeDefaultDescription
--versionintSchema version (required)
--reasonstringReason for deleting the schema definition
--server-sstringServer URL override

--reason <text> records an optional explanation with the archived old definition.

Output:

Deleted schema order.created (v1)

Read archived definitions for one event name and one numbered schema version. --version is required and must be positive. Each version has its own revision sequence, starting at 1. A revision contains the old document preserved before replacement or deletion, including its description and the mutating actor’s ID.

Terminal window
ironflow event schema history <event-name> --version <version> [flags]
FlagTypeDefaultDescription
--versionintRequired positive schema version
--revisionint64Retrieve one positive revision as full JSON
--limitint50Page size, maximum 200
--before-revisionint64Exclusive cursor for older revisions
--jsonboolfalseFull response as JSON
--server, -sstringServer URL override

Lists run newest first. JSON includes entries, has_more, and next_before_revision, which is zero on the last page. Do not combine --revision with pagination flags. Missing exact revisions return an error; missing history returns an empty list. Reads require events:subscribe permission in the selected environment. Text output has the columns REVISION, VERSION, RECORDED AT, CHANGE, ACTOR and REASON. When more revisions exist, it ends with a Next page: --before-revision <n> line.

Terminal window
ironflow event schema history order.created --version 1 --limit 10
ironflow event schema history order.created --version 1 --before-revision 12 --json
ironflow event schema history order.created --version 1 --revision 3 --json
ironflow event schema delete order.created --version 1 --reason "retired producer"

Example exact-revision JSON:

{
"entry": {
"event_id": "history-event-id",
"revision": "2",
"previous_definition": {
"event_name": "order.created",
"environment_id": "env-production",
"version": 1,
"schema_json": "{\"type\":\"object\"}",
"description": "Order payload"
},
"actor_id": "api-key-id",
"change_reason": "retired producer",
"change_type": "deleted",
"recorded_at": "2026-10-03T04:00:00Z"
}
}

Protobuf JSON represents int64 revision numbers as strings.

Initial creation and identical registration create no history. History remains readable after deletion; re-creating that same version continues its revision sequence on the next change. Changes made before this feature are unavailable.

Report whether event-schema enforcement is actually enforcing anything.

Enforcement is opt-in and off by default, and it has several ways to accept every payload without validating it. From outside, all of them look exactly like “every payload was clean”: an operator sets IRONFLOW_EVENT_SCHEMA_ENFORCEMENT=reject, sees zero rejections, and cannot tell which they are in. This command tells them apart (#1958).

Terminal window
ironflow event schema check [event-name] [flags]

Arguments:

ArgumentRequiredDescription
event-nameNoReport on one event name only (default: every schema)

Flags:

FlagShortTypeDefaultDescription
--windowint0Traffic sample window in hours (0 = default, 24)
--jsonboolfalseOutput as JSON
--server-sstringServer URL override

Verdicts:

VerdictMeaning
enforcingEvents at this version, all validated against this schema
partialSome events at this version validated against this schema
unvalidatedEvents at this version, none validated against this schema
unusedEvents of this name arrive, but at a different version
no-trafficNo events of this name in the window
permissiveThe schema compiles but accepts every payload
brokenThe stored schema does not compile; enforcement fails open

permissive is the one to read twice. A JSON Schema that compiles is not necessarily one that constrains: Draft 2020-12 treats an unrecognized keyword as an annotation, so {"foo":"bar"} is a valid schema that accepts every payload, exactly as {} does. Registering a sample payload by mistake succeeds and enforces nothing. Registration cannot reject these — {} is a legitimate permissive schema — so this report is where they surface. The check is a heuristic (it asks whether the schema rejects any of six probe documents), and it errs toward reporting permissive only when a schema really does accept every JSON type.

unvalidated means the events reached the store without being checked — because the mode was off, or the name was ungoverned at the time, or the stored schema would not compile. It is not a claim that the payloads were bad.

Output:

Enforcement mode: reject
Traffic window: last 24h
EVENT VER HASH VERDICT DETAIL
order.created 1 3f2a91c04b7e5d18 enforcing 340 events at v1 in the last 24h, all validated against this schema
order.created 2 9b1e77c2aa04f6d3 unused 340 events in the last 24h, none at v2 — they arrive at v1 (340). Version matching is exact, so this schema governs none of them.
user.signup 1 c40de9f1b2a83057 permissive schema compiles but rejects nothing — every payload satisfies it. Registering a sample payload instead of a schema looks exactly like this.

With the mode off, the table still renders and a banner says so — the verdicts then describe what would happen.

Counts are a sample of the newest matching events, not lifetime totals. When the sample hits its scan cap the header says (sampled).

Examples:

Terminal window
ironflow event schema check
ironflow event schema check order.created
ironflow event schema check --window 168
ironflow event schema check --json

Test how an event would be transformed between schema versions.

Terminal window
ironflow event upcast <event-name> [flags]

Arguments:

ArgumentRequiredDescription
event-nameYesThe event name to upcast

Flags:

FlagShortTypeDefaultDescription
--fromintSource version (required)
--tointTarget version (required)
--datastringEvent data as JSON
--data-filestringPath to JSON file with data (- reads stdin)
--jsonboolfalseOutput as JSON
--server-sstringServer URL override

Data input follows the same rules as emit (flag or file, --data-file - for stdin).

Output:

Steps applied:
FROM TO DESCRIPTION
1 2 added priority field
Result data:
{
"orderId": "123",
"customerId": "456",
"priority": "normal"
}

Examples:

Terminal window
ironflow event upcast order.created --from 1 --to 2 --data '{"orderId":"123"}'
ironflow event upcast order.created --from 1 --to 2 --data-file event.json
ironflow event upcast order.created --from 1 --to 3 --data '{}' --json

Irreversibly replace an event’s data with a placeholder.

Terminal window
ironflow event redact <event-id> [flags]

The row keeps its id, name, sequence and entity version, so replay ordering and optimistic concurrency are unaffected and reducers receive the placeholder in the payload’s place. The SDK upcaster chains skip a redacted payload rather than migrate it, so its marker survives. The placeholder is {"$redacted": true, "sha256": "...", "redactedAt": "..."}; the hash is of the original bytes and nothing recovers them from it. SDKs expose isRedacted(payload) so a reducer can tell it from real state.

If the event belongs to an entity stream, that stream’s snapshots are dropped in the same transaction. Their state is derived from the bytes being removed, so leaving them would keep serving the original content and the reducer would never see the placeholder. The next read re-reduces from the events.

Copies that are not yet published change in the same transaction. A pending outbox row and an outbox dead letter both take the placeholder, so the event publishes the placeholder, and so does a later ironflow outbox dlq requeue. An entity row keeps its envelope, with the placeholder in data.

Destructive and irreversible; prompts for confirmation unless --yes is passed. Needs the events:redact action, which only the admin role holds by default.

Four things this does not reach:

  • Projection state. A read model that folded this payload into its state keeps it; Ironflow never rewrites projection state. Rebuild the projection if it needs to forget it too.
  • The runs the event triggered. A run’s input holds a copy of the same payload, and so does its run.created audit row. Use ironflow run redact for those.
  • A copy already published to a stream, which survives until its own retention window expires (seven days on PUBSUB; EVENTS has no age expiry and requires terminal reclamation). A subscriber that received it keeps it. The worker reads each row just before it publishes. A publish past that read when the redaction commits counts as published, so it can still send the original.
  • An object-storage copy whose cleanup fails. Snapshot blobs are swept on a best-effort basis after the rows are scrubbed; a failed sweep is logged and the object is left behind with nothing to reclaim it.

Arguments:

ArgumentRequiredDescription
event-idYesThe event ID to redact

Flags:

FlagShortTypeDefaultDescription
--server-sstringServer URL override
--yesboolfalseSkip confirmation prompt

Output:

Redacted event ev-abc123

Examples:

Terminal window
ironflow event redact ev_abc123
ironflow event redact ev_abc123 --yes