---
name: fluent-event-api
description: Understand and work with the Fluent Commerce Event API. Covers event types, categories, statuses, routing, context model, filtering, execution model, run-once workflows, log actions, and operational query patterns for debugging workflows dynamically, including mutation/webhook/scheduled payload forensics from audit actions. Triggers on "event api", "event types", "event categories", "query events", "event model", "event status", "analyze events", "event history", "bulk events", "run once", "log action".
user-invocable: true
read-only: true
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
argument-hint: [--entity-ref <ref>] [--entity-type ORDER|FULFILMENT] [--status FAILED|SUCCESS|SCHEDULED] [--type ORCHESTRATION|ORCHESTRATION_AUDIT]
cursor-tier: manual
---

# Fluent Commerce Event API

Comprehensive reference for understanding and querying the Fluent Commerce Event API. Covers the event data model, how the orchestration engine processes events, all filter parameters, execution threading, run-once workflows, log actions, and operational query patterns for debugging workflows dynamically.

## Ownership Boundary

This skill owns event data model knowledge, query patterns, execution model, and operational analysis.

- **Sending events** (build/send/dryRun flows) → `/fluent-mcp-tools`
- **One-call runtime forensics** (mutations/webhooks/scheduled/exceptions) → `event.flowInspect` via `/fluent-mcp-tools`
- **Debugging a specific stuck entity** → `/fluent-trace`
- **Testing event sequences** → `/fluent-e2e-test`
- **Discovering available actions at a status** → `/fluent-transition-api`

## Skill Type: Reference

This is a **reference skill** — it provides event data model knowledge, query patterns, and debugging guidance but does not send events or modify environments. For sending events, use `event.build` + `event.send` via `/fluent-mcp-tools`. For runtime forensics, use `event.flowInspect` via `/fluent-mcp-tools`.

> **Canonical reference:** This skill is the single source of truth for event API filter syntax, query patterns, and the event data model. Other skills that need event filtering should reference `/fluent-event-api` rather than duplicating the filter parameter documentation.

## REST API Reference

### Endpoints

| Method | Path | Description | Mode |
|--------|------|-------------|------|
| GET | `/api/v4.1/event/{eventId}` | Get a single event by ID | — |
| GET | `/api/v4.1/event` | List/filter events with query parameters | — |
| POST | `/api/v4.1/event/async` | Create event asynchronously | Async (recommended for integrations) |
| POST | `/api/v4.1/event/sync` | Create event synchronously | Sync (UI user actions only) |

**Base URL:** `https://<accountId>.<env>.api.fluentretail.com/api/v4.1/event`
**Auth:** OAuth required. **Scheme:** HTTPS only. **Content-Type:** `application/json`

### API Limits and Defaults

| Constraint | Value |
|------------|-------|
| Request size limit | 10 MB (returns HTTP 413 if exceeded) |
| Max time range for GET /event | Typically **4 months back + 1 month forward** from current time (API returns error if exceeded; treat validation errors as runtime truth for your tenant) |
| Recommended time range | 5 minutes (due to high event volume) |
| Default `from` | Usually today minus ~30 days (tenant-dependent) |
| Default `to` | Now |
| Default `count` | 100 |
| Max `count` (REST API) | 5,000 (may timeout with large result sets) |

**MCP vs REST count limits:** The MCP `event.list` tool caps at 500 per request. The REST API supports up to 5,000 but may timeout with large result sets. For aggregate analytics across many events, use `metrics.topEvents` (client-side aggregation across `event.list` pages) or `event.list` with narrow time windows and targeted filters (`eventStatus`, `category`, `eventType`). Use `metrics.query` for PromQL-based Prometheus queries when available.

**Window guardrail:** Treat Event API validation errors as runtime truth for your tenant. If a query window is rejected, shrink the interval and paginate (do not rely on hardcoded global limits).

**Scheduled events:** Once created, scheduled events cannot be cancelled or modified. Monitor via `event.list` with `eventStatus: "SCHEDULED"`. The event will process when its scheduled time arrives.

### POST Request Body (async and sync)

```json
{
  "name": "EventName",
  "retailerId": "1",
  "entityType": "ORDER",
  "entityId": "1234",
  "entityRef": "ON-1234",
  "rootEntityType": "ORDER",
  "rootEntityId": "1234",
  "rootEntityRef": "ON-1234",
  "attributes": { "key": "value" }
}
```

**Required fields:** `name`, `entityType`, `rootEntityType`, plus at least one of `entityId`/`entityRef` and one of `rootEntityId`/`rootEntityRef`.
**retailerId:** Required when authenticated as an Account User (account-level users may access multiple retailers).

### entityId vs entityRef — Legacy and New Domains

| Identifier | Use For | Examples |
|------------|---------|---------|
| `entityId` | Legacy entities | ORDER, FULFILMENT, LOCATION, FULFILMENT_OPTIONS |
| `entityRef` | Newer entities | VIRTUAL_POSITION, VIRTUAL_CATALOGUE, INVENTORY_CATALOGUE, INVENTORY_POSITION, BILLING_ACCOUNT, RETURN_ORDER |

Both fields can be supplied together. For legacy entities, `entityId` is the primary lookup. For newer entities (global inventory, billing, returns), `entityRef` is the primary lookup.

### Pre-Send Validation Checklist (Event Contract Guard)

Before sending an event (`event.send` or raw POST), validate:

1. `name` matches an intended ruleset name (or a known status-trigger flow).
2. `entityType` and `rootEntityType` are present and accurate.
3. At least one identifier exists for each level:
   - entity: `entityId` or `entityRef`
   - root entity: `rootEntityId` or `rootEntityRef`
4. `retailerId` is set when acting as an account-level user.
5. Required event attributes are present:
   - check `workflow.transitions` (`userActions[].attributes`) and/or rule contracts from `plugin.list`.
6. Time-window follow-up is prepared for async sends:
   - query with `event.list` using entity/root context + bounded `from/to` window.

### Strict User Action Event Contract (Anti-Hallucination)

When an event originates from a user action:

1. Use `workflow.transitions` as the runtime contract source.
2. Send `name` exactly as `userActions[].eventName` (never infer from labels).
3. Send only documented `userActions[].attributes` keys and types (do not invent payload keys).
4. If an expected action is missing, verify ALL THREE mandatory Transition API params: `module` (specific name — `"all"` returns NOTHING), `flexType`, and `flexVersion`. Omitting any one silently returns empty.
5. If actions still missing after verifying params, check `context[].modules` for visibility drift (module name must match manifest setting suffix: `fc.mystique.manifest.<module>` → `<module>`).

### Sync Response

The sync endpoint (`/event/sync`) returns a richer response than async:

```json
{
  "eventId": "uuid",
  "entityId": "994",
  "eventStatus": "COMPLETE"
}
```

Possible `eventStatus` values in sync response: `COMPLETE`, `FAILED`, `NO_MATCH`.

`NO_MATCH` means no ruleset matched the incoming event — the event name didn't match any ruleset name, and no status-trigger ruleset matched either. This usually indicates a workflow configuration issue.

### Async Response

The async endpoint (`/event/async`) returns only the event ID:

```json
{ "id": "uuid" }
```

Poll `event.list` with entity context and a time window to check processing result.

## Event Data Model

### Event Structure

Every event in Fluent Commerce has this shape:

```json
{
  "id": "uuid",
  "name": "EventName",
  "type": "ORCHESTRATION | ORCHESTRATION_AUDIT | API | GENERAL | ...",
  "accountId": "ACCOUNT_NAME",
  "retailerId": "2",
  "category": "ORDER WORKFLOW | ACTION | ruleSet | exception | ...",
  "context": {
    "sourceEvents": ["parent-event-uuid"],
    "entityType": "ORDER | FULFILMENT | VIRTUAL_CATALOGUE | ...",
    "entityId": "6611",
    "entityRef": "ORDER_REF_001",
    "rootEntityType": "ORDER",
    "rootEntityId": "6611",
    "rootEntityRef": "ORDER_REF_001"
  },
  "eventStatus": "SUCCESS | FAILED | COMPLETE | SCHEDULED | PENDING | NO_MATCH",
  "attributes": [
    { "name": "key", "value": "val", "type": "STRING | INTEGER | BOOLEAN | OBJECT" }
  ],
  "source": "Fluent-API | <hashcode>.<RulesetName> | plugin",
  "generatedBy": "username | Rubix User | ACCOUNT-RETAILER-rubix",
  "generatedOn": "ISO-8601 timestamp",
  "recordedBy": "username | Rubix User",
  "recordedOn": "ISO-8601 timestamp",
  "meta": null
}
```

### Event Types

| Type | What It Represents | Who Generates It |
|------|-------------------|-----------------|
| `ORCHESTRATION` | A workflow trigger event — an instruction to the orchestration engine to process rules | External API calls, `SendEvent` rules, entity creation (`CREATE` event), scheduled events |
| `ORCHESTRATION_AUDIT` | An audit trail record of what happened during rule execution. One `ORCHESTRATION` event produces multiple `ORCHESTRATION_AUDIT` children | The orchestration engine (Rubix) internally |
| `API` | A REST API call record (legacy audit) | The Fluent API layer when REST endpoints are called |
| `GENERAL` | General system activity record (non-triggering) | Various internal platform components |
| `INTEGRATION` | Integration event record | Integration subsystems |
| `SECURITY` | Security-related event record | Authentication and authorization subsystems |

**Key insight:** `ORCHESTRATION` and `ORCHESTRATION_AUDIT` are the primary types for workflow analysis. `API`, `GENERAL`, `INTEGRATION`, and `SECURITY` are informational — they describe what happened but do not trigger workflow execution.

### Event Categories

| Category | Meaning | Type |
|----------|---------|------|
| `ORDER WORKFLOW` | Workflow orchestration trigger event (the inbound event) | `ORCHESTRATION` |
| `ACTION` | A rule action executed during ruleset processing (SetState, SendEvent, Send Webhook) | `ORCHESTRATION_AUDIT` |
| `ruleSet` | A ruleset-level execution record (start/stop timing) | `ORCHESTRATION_AUDIT` |
| `rule` | An individual rule execution record | `ORCHESTRATION_AUDIT` |
| `exception` | A rule or engine exception during processing | `ORCHESTRATION_AUDIT` |
| `snapshot` | An entity snapshot taken during execution | `ORCHESTRATION_AUDIT` |
| `CUSTOM` | A log action event emitted by custom rule code via `context.action().log()` | `ORCHESTRATION_AUDIT` |
| `BATCH` | Batch processing events | `ORCHESTRATION_AUDIT` |

### Event Statuses

| Status | Meaning | Applies To |
|--------|---------|-----------|
| `SUCCESS` | Event processed or action completed successfully | Both types |
| `FAILED` | Event processing or action failed | Both types |
| `COMPLETE` | Workflow event fully processed (all rules executed) | `ORCHESTRATION` |
| `SCHEDULED` | Future-dated event, not yet processed | `ORCHESTRATION` |
| `PENDING` | Event queued, waiting for processing | `ORCHESTRATION` |
| `NO_MATCH` | No ruleset matched the incoming event | `ORCHESTRATION` |

**Status transitions:**
```
PENDING → (engine picks up) → SUCCESS / FAILED / COMPLETE / NO_MATCH
SCHEDULED → (scheduled time arrives) → PENDING → SUCCESS / FAILED / COMPLETE / NO_MATCH
```

### Constants Mini-Reference (Canonical Values)

Use these values when filtering and when writing diagnostics:

| Constant group | Canonical values |
|---|---|
| `eventType` | `ORCHESTRATION`, `ORCHESTRATION_AUDIT`, `API`, `GENERAL`, `INTEGRATION`, `SECURITY` |
| `eventStatus` | `SUCCESS`, `FAILED`, `COMPLETE`, `SCHEDULED`, `PENDING`, `NO_MATCH` |
| `category` (common) | `ORDER WORKFLOW`, `ACTION`, `ruleSet`, `rule`, `exception`, `snapshot`, `CUSTOM`, `BATCH` |

Treat additional values as environment-dependent extensions; do not hard-fail on unknown values.

### Enum Normalization (Cross-Doc Variants)

Some tenant docs and analytics layers use alias values. Normalize them before reasoning:

| Semantic meaning | Canonical Event API value | Alias values seen in docs/tools |
|---|---|---|
| Inbound orchestration category | `ORDER WORKFLOW` | `ORDER_WORKFLOW` |
| Failed terminal state | `FAILED` | `ERROR` |
| In-flight / not-terminal | `PENDING` (and `SCHEDULED`) | `PROCESSING` |
| Successful terminal state | `COMPLETE` / `SUCCESS` | `SUCCESS` |

Use canonical Event API values in `event.list` filters. Keep alias mapping only for interpretation/reporting.

### Orchestratable Entity Types

**Root Entity Types** (top-level entities that own workflows):

`ORDER`, `LOCATION`, `FULFILMENT_OPTIONS`, `PRODUCT_CATALOGUE`, `INVENTORY_CATALOGUE`, `VIRTUAL_CATALOGUE`, `CONTROL_GROUP`, `RETURN_ORDER`, `BILLING_ACCOUNT`, `JOB`

**All Entity Types** (includes child/sub-entities):

`ORDER`, `FULFILMENT`, `FULFILMENT_CHOICE`, `ARTICLE`, `CONSIGNMENT`, `CARRIER_CONSIGNMENT`, `LOCATION`, `WAVE`, `FULFILMENT_OPTIONS`, `FULFILMENT_PLAN`, `PRODUCT_CATALOGUE`, `CATEGORY`, `PRODUCT`, `INVENTORY_CATALOGUE`, `INVENTORY_POSITION`, `INVENTORY_QUANTITY`, `VIRTUAL_CATALOGUE`, `VIRTUAL_POSITION`, `CONTROL_GROUP`, `CONTROL`, `RETURN_ORDER`, `RETURN_FULFILMENT`, `BILLING_ACCOUNT`, `CREDIT_MEMO`, `FINANCIAL_TRANSACTION`, `MANIFEST`, `BATCH`

**Additional traceable entity types** (appear in event context for tracing but typically don't own workflows):

`NETWORK`, `STORE_ADDRESS`

### Entity Hierarchy — Root to Child Mapping

When sending events, `rootEntityType` must be the top-level entity that owns the workflow. `entityType` targets the specific entity within that hierarchy. Use this table to determine the correct `rootEntityType` for any `entityType`:

| Root Entity Type | Allowed Child Entity Types | Workflow Pattern |
|---|---|---|
| `ORDER` | `FULFILMENT`, `ARTICLE`, `CONSIGNMENT`, `CARRIER_CONSIGNMENT`, `MANIFEST`, `FINANCIAL_TRANSACTION`, `FULFILMENT_OPTIONS`, `FULFILMENT_PLAN` | `ORDER::<subtype>` (e.g., `ORDER::HD`, `ORDER::CC`) |
| `LOCATION` | `WAVE` | `LOCATION::<subtype>` |
| `FULFILMENT_OPTIONS` | `FULFILMENT_PLAN` | `FULFILMENT_OPTIONS::<subtype>` |
| `PRODUCT_CATALOGUE` | `CATEGORY`, `PRODUCT` | `PRODUCT_CATALOGUE::<subtype>` |
| `INVENTORY_CATALOGUE` | `INVENTORY_POSITION`, `INVENTORY_QUANTITY` | `INVENTORY_CATALOGUE::<subtype>` |
| `VIRTUAL_CATALOGUE` | `VIRTUAL_POSITION` | `VIRTUAL_CATALOGUE::<subtype>` |
| `CONTROL_GROUP` | `CONTROL` | `CONTROL_GROUP::<subtype>` |
| `RETURN_ORDER` | `RETURN_FULFILMENT` | `RETURN_ORDER::<subtype>` |
| `BILLING_ACCOUNT` | `CREDIT_MEMO` | `BILLING_ACCOUNT::<subtype>` |
| `JOB` | `BATCH` | `JOB::<subtype>` |

**Self-referencing:** When the event targets the root entity itself, `entityType` = `rootEntityType` (e.g., an ORDER event has both set to `ORDER`).

**FULFILMENT_OPTIONS note:** This entity type appears both as a root entity (owns its own workflow) and as a child of ORDER in some contexts. When targeting FULFILMENT_OPTIONS directly, use it as `rootEntityType`. When tracing from an order perspective, the order's FULFILMENT_OPTIONS events will have `rootEntityType=ORDER`.

### Event Context — Entity vs Root Entity

Every event has a **target entity** and an optional **root entity**:

| Field | Purpose | Example |
|-------|---------|---------|
| `entityType` | The entity this event targets | `FULFILMENT` |
| `entityId` | Numeric ID of the target entity | `10269` |
| `entityRef` | Reference of the target entity | `107ae9df-9441-...` |
| `rootEntityType` | The top-level parent entity | `ORDER` |
| `rootEntityId` | Numeric ID of the root entity | `6611` |
| `rootEntityRef` | Reference of the root entity | `E2E_HD_20260222_RUN1` |

**Why this matters:** A fulfilment event has `entityType=FULFILMENT` but `rootEntityType=ORDER`. This lets you trace all events across an entire order lifecycle — including its child fulfilments — by filtering on `rootEntityRef`.

### Source Events — Tracing Causality

The `context.sourceEvents` array contains the parent event IDs that caused this event:

- `ORCHESTRATION` events from `event.send` have `sourceEvents: []` (they are root causes)
- `ORCHESTRATION_AUDIT` events have `sourceEvents: ["<parent-orchestration-event-id>"]`
- `ORCHESTRATION` events created by `SendEvent` rules have `sourceEvents: ["<audit-event-that-sent-them>"]` — but only sometimes; Fluent doesn't always populate this

**Caveat:** `sourceEvents` can be missing/incomplete in some environments. For causality, combine it with time windows and entity/root-entity context.

### Causality Fallback Playbook (When `sourceEvents` Is Sparse)

When direct parent pointers are absent:

1. Fetch anchor event with `event.get(eventId)`.
2. Build a tight correlation window around `generatedOn` (for example `-1s` to `+30s`).
3. Query `event.list` constrained by:
   - `context.entityRef` / `context.entityType`
   - `context.rootEntityRef` / `context.rootEntityType` (for cross-entity flows)
   - `eventType: ORCHESTRATION_AUDIT`
4. Order by timestamp and group by `category` (`ruleSet`, `rule`, `ACTION`, `exception`).
5. Reconstruct chain by sequence:
   - trigger `ORCHESTRATION` -> related audit trail -> next emitted `ORCHESTRATION`.
6. Validate inferred edges with rule/action evidence (`attributes.Event Name`, webhook attributes, exception fields).

### The `source` Field

| Value Pattern | Meaning |
|---------------|---------|
| `Fluent-API` | Event sent via REST API (`event.send`) |
| `<hashcode>.<RulesetName>` | Generated by the orchestration engine during ruleset execution |
| `plugin` | Generated by a custom rule (typically log action events) |
| `null` | Exception or system-generated event |
| `my_admin` (or username) | API event tied to a specific user |

### Event Attributes

Attributes carry data with events. Different event categories have different attribute patterns:

**ACTION events (rule audit):**
- `Event Name` — the event name a SendEvent rule dispatched
- `Event` — full nested event object (for SendEvent audit trail)
- `Future Dated` — boolean, whether the event is scheduled for the future
- `Request Endpoint`, `Response Body`, `Response code`, `Response Headers` — for webhook audit
- `startTimer`, `stopTimer` — execution timing in epoch milliseconds

**Exception events:**
- `exception` — full Java exception object with stackTrace, message, code
- `lastRule` — the rule that was executing when the exception occurred (can be null)
- `lastRuleSet` — the ruleset being executed
- `message` — human-readable error message

**Log Action events (category=CUSTOM):**
- `action` — the action label
- `message` — the log message string
- `detailedMessage` — the detailed log message string

## Event Execution Model

### Execution Context

When an `ORCHESTRATION` event is received by the Rubix orchestration engine:

1. **Initiate Execution Context** — includes the event and the entity specified by the event
2. **Load workflow** — locate the appropriate workflow based on entity type, subtype, and version
3. **Match rulesets** — find rulesets matching the event signature (see Ruleset Matching below)
4. **Execute sequentially** — all matching rulesets are executed one by one in sequence

### Ruleset Matching

The engine matches events to rulesets using four criteria:

1. **Event Name = Ruleset Name** (exact match, case-sensitive) — primary match
2. **Entity Type** — e.g., `ORDER`
3. **Entity Subtype** — e.g., `HD`
4. **Entity Status** — e.g., `BOOKED` (via `triggers: [{ "status": "BOOKED" }]`)

**Priority:** If both a name-match and a status-trigger match exist, the name-match takes priority. If no ruleset matches, the event gets `NO_MATCH` status.

### Threading Model

- **Single-threaded execution:** Each event that triggers execution is processed in its own single thread. The workflow execution is linear.
- **No parallel split:** There is no concurrent processing within the same execution context.
- **Flow control events (same thread):** If a rule produces an event intended to trigger another ruleset **within the same workflow/root entity**, it is matched and queued for execution within the same execution thread.
- **Cross-workflow events (different thread):** Events produced for a **different workflow or different root entity** are NOT executed in the same context — they are processed separately by Rubix in a different thread.

### Internal Queues

The engine uses two internal queues:

- **Internal Event Queue** — holds events waiting for ruleset matching and execution
- **Internal Action Queue** — holds actions (webhooks, scheduled events, mutations) produced by rules; these are processed separately after rule execution

## How Events Route to Rulesets

```
1. Receive ORCHESTRATION event (name, entityType, entityStatus, entitySubtype)
2. Find workflow for flexType = entityType::entitySubtype (e.g., ORDER::HD)
3. Match ruleset by:
   a. Ruleset name == event name (exact match, case-sensitive)
   b. OR ruleset has triggers: [{ "status": "<entityStatus>" }] (status trigger)
4. Execute all rules in the matched ruleset sequentially
5. For each rule action, write ORCHESTRATION_AUDIT event
6. If exception, write ORCHESTRATION_AUDIT with category "exception"
7. If no match, write event with status NO_MATCH
```

## Log Actions (Custom Audit Events)

Custom rules can emit log events for monitoring and audit using:

```java
context.action().log(message, detailedMessage, attributes);
```

These produce `ORCHESTRATION_AUDIT` events with `category=CUSTOM` and `name=CREATE_Log`, `source=plugin`.

**Query log action events:**
```
event.list({
  "category": "CUSTOM",
  "from": "2026-02-20T00:00:00Z",
  "to": "2026-02-20T23:59:59Z",
  "count": 200
})
```

Log action events are useful for business monitoring, audit trails, and debugging custom rule behavior. The `attributes` array contains the `message`, `detailedMessage`, and any additional key-value pairs passed by the rule.

## Manual Event with Run-Once Workflow

The Fluent platform supports sending events with a workflow "attached" in the `meta` section. Rubix executes only the rules defined in the attached workflow — this is primarily used for operational recovery and manual intervention.

### When to Use

- Re-trigger a failed webhook without re-running the entire ruleset
- Execute a specific rule on an entity for data correction
- Run a subset of rules without modifying the deployed workflow
- One-off operational tasks

### Structure

```json
{
  "name": "EventName",
  "accountId": "ACCOUNT_ID",
  "retailerId": "1",
  "entityType": "FULFILMENT",
  "entityId": "143",
  "meta": {
    "workflow": {
      "retailerId": "1",
      "version": "1.0",
      "rulesets": [
        {
          "name": "EventName",
          "type": "FULFILMENT",
          "eventType": "NORMAL",
          "rules": [
            {
              "name": "ACCOUNT.namespace.RuleName",
              "props": { "key": "value" }
            }
          ],
          "triggers": [],
          "userActions": []
        }
      ]
    }
  }
}
```

### Rules

- The event `name` **must match** the ruleset `name` inside `meta.workflow`
- The `entityType` at top level **must match** the ruleset `type`
- `triggers: []` and `userActions: []` should be left empty
- Send via the **sync** endpoint: `POST /api/v4.1/event/sync`
- **Any rule** available in the account can be executed — it does not need to exist in the entity's current deployed workflow

### What Gets Executed

| Action | Executed? |
|--------|-----------|
| Rules in attached workflow | Yes |
| Webhooks | Yes |
| Scheduled events | Yes |
| Mutations | Yes |
| Inline (flow control) events | **No** (ignored) |

## MCP Tool: `event.list` — All Filter Parameters

```
event.list({
  // Event identity
  "eventId": "<EVENT_UUID>",                // Filter by specific event ID (alias: id)

  // Entity filters
  "context.entityRef": "ORDER_REF",        // Filter by target entity ref
  "context.entityType": "ORDER",           // Filter by target entity type
  "context.entityId": "6611",              // Filter by target entity ID
  "context.rootEntityRef": "ORDER_REF",    // Filter by root entity ref
  "context.rootEntityType": "ORDER",       // Filter by root entity type
  "context.rootEntityId": "6611",          // Filter by root entity ID

  // Aliases (same as context.* equivalents)
  "entityRef": "ORDER_REF",               // Alias for context.entityRef
  "entityType": "ORDER",                  // Alias for context.entityType

  // Event filters
  "name": "ConfirmValidation",            // Filter by event name
  "eventStatus": "FAILED",               // Filter by status: FAILED, SUCCESS, COMPLETE, SCHEDULED, PENDING, NO_MATCH
  "eventType": "ORCHESTRATION",           // Filter by type: ORCHESTRATION, ORCHESTRATION_AUDIT, API, GENERAL, INTEGRATION, SECURITY
  "category": "exception",               // Filter by category: ORDER WORKFLOW, ACTION, ruleSet, rule, exception, snapshot, CUSTOM, BATCH

  // Time filters
  "from": "2026-02-20T00:00:00Z",        // Start of time window (ISO-8601)
  "to": "2026-02-22T23:59:59Z",          // End of time window (ISO-8601)

  // Pagination
  "count": 50,                            // Page size (1-500 via MCP tool; REST API supports up to 5000)
  "start": 1                              // Pagination offset (1-based)
})
```

**Multi-value filters:** The REST API accepts multiple values (List) for: `retailerId`, `eventType`, `category`, `context.rootEntityType`, `context.entityType`, `eventStatus`.

**Aliases:** `entityRef` = `context.entityRef`, `entityType` = `context.entityType`, `type` = `eventType`, `id` = `eventId`.

## Operational Query Patterns

### Pattern 1: Full Event Timeline for an Entity

```
event.list({
  "context.entityRef": "<ORDER_REF>",
  "context.entityType": "ORDER",
  "count": 100
})
```

### Pattern 2: All Events Across an Order and Its Children

Use `rootEntityRef` to capture ORDER + FULFILMENT + FULFILMENT_OPTION events:

```
event.list({
  "context.rootEntityRef": "<ORDER_REF>",
  "context.rootEntityType": "ORDER",
  "count": 200
})
```

### Pattern 3: Find Failed Events Across All Entities

```
event.list({
  "eventStatus": "FAILED",
  "from": "2026-02-22T00:00:00Z",
  "count": 50
})
```

### Pattern 4: Find Exception Details

Filter for exception audit events to get stack traces:

```
event.list({
  "category": "exception",
  "from": "2026-02-22T00:00:00Z",
  "count": 50
})
```

### Pattern 5: Trace What a Specific Event Triggered

1. Get the ORCHESTRATION event:
```
event.get({ "eventId": "<EVENT_ID>" })
```

2. Find all audit events it spawned:
```
event.list({
  "eventType": "ORCHESTRATION_AUDIT",
  "context.entityRef": "<ENTITY_REF>",
  "from": "<event_timestamp_minus_1s>",
  "to": "<event_timestamp_plus_30s>",
  "count": 50
})
```

Match by checking `sourceEvents` array contains the parent event ID.

### Pattern 6: Find Scheduled (Future-Dated) Events

```
event.list({
  "eventStatus": "SCHEDULED",
  "context.entityRef": "<ENTITY_REF>",
  "count": 20
})
```

### Pattern 7: Webhook Execution Audit

```
event.list({
  "eventType": "ORCHESTRATION_AUDIT",
  "category": "ACTION",
  "name": "Send Webhook",
  "context.rootEntityRef": "<ENTITY_REF>",
  "count": 50
})
```

Each result's attributes contain: `Request Endpoint`, `Response code`, `Response Body`, `Response Headers`.

### Pattern 7b: Extract Mutation Request Payloads from ACTION Audit

Many mutation actions appear with empty/unknown `name`, but still include full dynamic GraphQL request metadata in attributes.

```
event.list({
  "eventType": "ORCHESTRATION_AUDIT",
  "category": "ACTION",
  "context.rootEntityRef": "<ENTITY_REF>",
  "count": 200
})
```

For each ACTION event, inspect:

- `attributes.request.queryType` (for example `DynamicUpdateMutation`)
- `attributes.request.queryName` (for example `updateOrder`, `updateFulfilment`)
- `attributes.request.queryString`
- `attributes.request.variables.values.input` (actual mutation payload)
- `attributes.response.inner` (mutation result entity reference/type)

Do not rely on `name` alone for mutation detection.

### Pattern 7c: Future-Dated / Scheduled Evidence from ACTION Payload

`eventStatus=SCHEDULED` may not show all delayed dispatches for a root ref. Also inspect ACTION payloads:

- `attributes["Future Dated"] == true`
- `attributes.Event.scheduledOn`
- `event.get(...).event.meta.scheduledOn`

This reveals when delayed events were enqueued and what target entity they were sent to.

### Pattern 8: Rule Execution Timing

Find slow-running rulesets by checking `startTimer`/`stopTimer` attributes:

```
event.list({
  "category": "ruleSet",
  "eventType": "ORCHESTRATION_AUDIT",
  "context.entityRef": "<ENTITY_REF>",
  "count": 100
})
```

Calculate duration: `stopTimer - startTimer` (milliseconds).

### Pattern 9: NO_MATCH Events (Workflow Gaps)

Find events that didn't match any ruleset — indicates missing workflow configuration:

```
event.list({
  "eventStatus": "NO_MATCH",
  "from": "2026-02-22T00:00:00Z",
  "count": 50
})
```

### Pattern 10: Log Action Events (Custom Audit)

```
event.list({
  "category": "CUSTOM",
  "from": "2026-02-22T00:00:00Z",
  "to": "2026-02-22T23:59:59Z",
  "count": 200
})
```

### Pattern 11: Legacy REST API Audit Events

```
event.list({
  "eventType": "API",
  "name": "POST /api/v4.1/order",
  "count": 100
})
```

### Pattern 12: Paginating Through Large Event Sets

```
# Page 1
event.list({ "context.rootEntityRef": "<REF>", "count": 100, "start": 1 })
# Page 2
event.list({ "context.rootEntityRef": "<REF>", "count": 100, "start": 101 })
# Continue while hasMore: true
```

## Reading Failed Events — What to Look For

### Exception Event Anatomy

```json
{
  "name": "com.fluentretail.rubix.exceptions.NotFoundException",
  "type": "ORCHESTRATION_AUDIT",
  "category": "exception",
  "eventStatus": "FAILED",
  "attributes": [
    {
      "name": "exception",
      "type": "OBJECT",
      "value": {
        "code": 404,
        "message": "Workflow for key -1 could not be found...",
        "stackTrace": [...]
      }
    },
    { "name": "lastRule", "value": null },
    { "name": "lastRuleSet", "value": null },
    { "name": "message", "value": "Workflow for key -1 could not be found..." }
  ]
}
```

### Common Exception Patterns

| Exception Class | Code | Cause | Fix |
|----------------|------|-------|-----|
| `NotFoundException` | 404 | No workflow found for entity type/subtype | Create or deploy workflow matching the `flexType` |
| `RuleExecutionException` | — | Rule threw during execution | Check `lastRule` and `lastRuleSet`, inspect rule source |
| `ValidationException` | 400 | Invalid event attributes or entity state | Check required attributes for the event |
| `AuthorizationException` | 403 | User lacks permission for the operation | Check retailerId scope and user roles |

### Key Fields for Diagnosis

| Field | Where | What It Tells You |
|-------|-------|------------------|
| `eventStatus` | Event responses | Processing status (SUCCESS, FAILED, COMPLETE, NO_MATCH, etc.) |
| `attributes.lastRule` | Exception events | Which rule was executing when it failed |
| `attributes.lastRuleSet` | Exception events | Which ruleset was executing |
| `attributes.message` | Exception events | Human-readable error description |
| `attributes.exception.stackTrace` | Exception events | Full Java stack trace for root cause |
| `source` | Audit events | `<hashcode>.<RulesetName>` — which ruleset generated this audit |
| `context.sourceEvents` | Audit events | Parent event ID — trace causality chain |
| `attributes.startTimer` / `stopTimer` | Audit events | Execution timing in epoch ms |

## Event Naming Conventions

| Pattern | Example | When Used |
|---------|---------|-----------|
| `CREATE` | Auto-generated | Entity creation triggers workflow |
| `Confirm*` | `ConfirmValidation`, `ConfirmPick` | User-initiated progression actions |
| `Cancel*` | `CancelOrder`, `CancelFulfilment` | Cancellation actions |
| `Process*` | `ProcessFulfilment` | Internal workflow progression |
| `Check*` | `CheckAllFulfilmentsComplete` | Gate/verification events |
| `*Expiry` | `FulfilmentExpiry` | Scheduled timeout events |
| `CREATE_Log` | Custom rule output | Log action events (category=CUSTOM) |
| Rule action names | `Send Event`, `Send Webhook`, `Change State` | ORCHESTRATION_AUDIT names from rule actions |
| Exception class names | `com.fluentretail.rubix.exceptions.*` | ORCHESTRATION_AUDIT names for exceptions |
| `snapshot` | Entity snapshot | Snapshot audit events |

## Common Integration Event Patterns

Practical event payload templates for common integration scenarios. All use `POST /event/async`.

### Custom Inventory Update

When Batch API cannot satisfy inventory requirements:

```json
{
  "name": "DeltaInventoryUpdate",
  "retailerId": "1",
  "rootEntityType": "INVENTORY_CATALOGUE",
  "rootEntityRef": "INV-CAT-001",
  "entityType": "INVENTORY_POSITION",
  "entityRef": "POS-SKU-LOC-001",
  "attributes": { "skuRef": "SKU-001", "locationRef": "LOC-001", "quantityDelta": 50 }
}
```

### PIM Product Creation

External Product Master updates:

```json
{
  "name": "CreateProduct",
  "retailerId": "1",
  "rootEntityType": "PRODUCT_CATALOGUE",
  "rootEntityRef": "MASTER-CATALOG",
  "entityType": "PRODUCT",
  "entityRef": "PROD-SKU-001",
  "attributes": { "productName": "Widget", "categoryRef": "CAT-001", "brandName": "Brand" }
}
```

### WMS Pick Confirmation

Fulfilment updates from Warehouse Management System:

```json
{
  "name": "ConfirmPick",
  "retailerId": "1",
  "rootEntityType": "ORDER",
  "rootEntityId": "12345",
  "entityType": "FULFILMENT",
  "entityId": "67890",
  "attributes": { "pickedItems": [{ "skuRef": "SKU-001", "quantityPicked": 2 }] }
}
```

### Carrier Tracking Update

```json
{
  "name": "TrackingUpdate",
  "retailerId": "1",
  "rootEntityType": "ORDER",
  "rootEntityId": "12345",
  "entityType": "CONSIGNMENT",
  "entityId": "11111",
  "attributes": { "trackingNumber": "1Z999AA1234567890", "status": "IN_TRANSIT", "carrierRef": "UPS" }
}
```

## Sync vs Async Event Dispatch

| Mode | Endpoint | Behavior | Use When |
|------|----------|----------|----------|
| `async` | `/event/async` | Event queued, returns immediately with `{ id }`. Poll `event.list` for result. | Standard workflow events, production use, middleware integrations |
| `sync` | `/event/sync` | Event processed synchronously. Returns `{ eventId, entityId, eventStatus }`. Blocks until complete. | UI user actions, testing, debugging, run-once workflows |

**Async is recommended for all external system integrations.** The sync endpoint is not designed to scale for middleware and should only be used when triggered by a real user action or for operational intervention.

**Gotcha:** Async processing time is environment-dependent (often seconds to tens of seconds). After sending, poll `event.list` with entity context and a time window; don't assume immediate completion.

## Cross-Entity Event Tracing

To build a complete picture of an order lifecycle across all entities:

1. **Get the order events:**
```
event.list({ "context.rootEntityRef": "<ORDER_REF>", "context.rootEntityType": "ORDER", "count": 200 })
```

2. **Group by entityType** — Separate ORDER, FULFILMENT, FULFILMENT_OPTIONS events

3. **Sort by generatedOn** — Build a chronological timeline

4. **Link parent → child** — Match `sourceEvents` arrays to connect triggers to their audit trail

5. **Identify the failure point** — Find the first FAILED or NO_MATCH event in chronological order

6. **Get exception details** — Filter for `category: "exception"` events near the failure timestamp

This gives you a complete causal chain: which event triggered which ruleset, which rule action failed, and what exception occurred.

## Event Contracts

An event contract is the implicit agreement between an event sender and the rulesets that consume it.

### Inbound Contract (What a Ruleset Expects)

- **Props:** Defined by `@ParamString`, `@ParamBoolean` annotations in rule source code
- **Event attributes:** Declared via `@EventAttribute` annotations, read via `event.getAttributes().get("name")` or `event.getAttribute("name", Type.class)` — NEVER via `DynamicUtils.getJsonPath`
- **Entity state:** Some rules assume the entity is in a specific status

**How to discover inbound contracts:**
1. `plugin.list({ name: "RuleName" })` → check `eventAttributes` field
2. `workflow.transitions` → `userActions[].attributes` shows required attributes for user-facing events
3. Rule source code: search for `@ParamString`, `@EventAttribute`, and `event.getAttributes()` patterns

### Outbound Contract (What a Ruleset Produces)

- **SendEvent rules** create new ORCHESTRATION events with `sourceEvents` linking back
- **SetState rules** change entity status, potentially triggering status-trigger rulesets
- **Mutations** modify entity data
- **Webhooks** send data to external systems

### Contract Violations

| Violation | Symptom | Diagnosis |
|-----------|---------|-----------|
| Missing event attribute | Rule reads null, silent failure or exception | Check `plugin.list` eventAttributes vs event.send attributes |
| Wrong attribute type | ClassCastException in rule execution | Check attribute types match rule expectations |
| Wrong entity status | Rule guard fails, no state change | Verify entity status matches ruleset trigger |
| Missing setting | Rule reads null setting value | Cross-reference rule's setting name with `settings` query |

## Integration Patterns

Compact patterns for common external system integration event flows.

### Inventory Sync (WMS/ERP)
- **Entity:** INVENTORY_CATALOGUE or INVENTORY_POSITION
- **Pattern:** External system → async event → inventory catalogue workflow → UpdateInventoryPosition rule
- **Key attributes:** sku, quantity, locationRef
- **Event name:** Varies by implementation (often custom event triggering status-based ruleset)

### Product Sync (PIM)
- **Entity:** PRODUCT_CATALOGUE
- **Event name:** `UPSERT_PRODUCT` or custom
- **Pattern:** PIM → batch ingestion or async event → product catalogue workflow
- **Key attributes:** productRef, variantRefs, catalogueRef

### Carrier / Shipment Updates
- **Entity:** FULFILMENT or CONSIGNMENT
- **Pattern:** Carrier webhook → middleware → async event → fulfilment workflow
- **Key attributes:** trackingNumber, carrierRef, statusUpdate, deliveredAt
- **Common events:** TrackingUpdate, DeliveryConfirmed (names vary by implementation)

### Order Intake
- **Entity:** ORDER
- **Event name:** `CREATE` (auto-generated on `createOrder` mutation)
- **Pattern:** Ecommerce platform → createOrder GraphQL mutation → ORDER workflow auto-triggers
- **Note:** The `CREATE` event is implicit — no explicit event.send needed. The mutation triggers it.
- **Full mutation reference:** `knowledge/platform/create-order-reference.md` — type tree, HD/CC/split patterns, fulfilmentChoice linkage, gotchas

### SendEvent Classification

When tracing `SendEvent` rule actions in audit events, classify the dispatch target to understand flow control:

| Classification | Detection | Meaning |
|---------------|-----------|---------|
| **Same entity** | `sendEvent.entityRef == sourceRule.entityRef` | Internal flow control — triggers another ruleset on the same entity |
| **Same workflow, different entity** | Same workflow type but different `entityRef` | Internal orchestration — coordinates between entities in the same workflow |
| **Cross-workflow** | Different workflow type or different `entityType` | External trigger — creates a cascade across workflow boundaries (ORDER→FULFILMENT, FULFILMENT→ARTICLE) |

Cross-workflow SendEvents are the primary mechanism for entity lifecycle cascades. When debugging stuck entities, trace these first — a missing or failed cross-workflow SendEvent is the most common cause of child entities never being created.

## Monitoring Patterns

### Business Monitoring

Track business execution for entities: why a fulfilment was assigned to a location, why an order moved to exception status, when a fulfilment is stuck too long.

| Mechanism | How |
|-----------|-----|
| Log action events | Custom rules emit `category=CUSTOM` events; poll via `event.list` |
| Webhook notifications | Configure webhook rules to notify monitoring systems |
| GraphQL reporting | Query entities stuck in statuses via `graphql.query` |
| Event polling | Poll `ORCHESTRATION` events for specific entity/status patterns |
| Scheduled events | Detect entities stuck in a status for too long via `*Expiry` events |

### Technical Monitoring

Track technical issues: rule failures, workflow exceptions, API errors, missing rulesets.

| Mechanism | How |
|-----------|-----|
| Exception events | Poll `category=exception` with `from/to` for stack traces and rule failure details |
| NO_MATCH detection | Poll `eventStatus=NO_MATCH` to find events that didn't trigger any ruleset |
| API error responses | Check REST/GraphQL response codes for failures |
| Log events | Custom rules can log technical exception details via `context.action().log()` |
