{
  "openapi": "3.0.0",
  "info": {
    "title": "Event Catalog API",
    "description": "Manages the catalog of business events available in epilot",
    "version": "0.1.0"
  },
  "tags": [
    {
      "name": "Event Catalog",
      "description": "API for managing business event catalog"
    }
  ],
  "security": [
    {
      "EpilotAuth": []
    },
    {
      "EpilotOrg": []
    }
  ],
  "paths": {
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "listEvents",
        "description": "Retrieve list of available business events",
        "tags": [
          "Event Catalog"
        ],
        "responses": {
          "200": {
            "description": "A JSON array of event objects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventConfig"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/events/{event_name}": {
      "get": {
        "operationId": "getEvent",
        "summary": "getEvent",
        "description": "Retrieve the configuration of a specific business event",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Event configuration object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventConfig"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "patchEvent",
        "summary": "patchEvent",
        "description": "Update the configuration of a specific business event for the organization",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEventPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated event configuration object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventConfig"
                }
              }
            }
          },
          "404": {
            "description": "Event not found"
          }
        }
      }
    },
    "/v1/events/{event_name}/json_schema": {
      "get": {
        "operationId": "getEventJSONSchema",
        "summary": "getEventJSONSchema",
        "description": "Retrieve the JSON Schema of a specific business event. Pass an optional\n`Epilot-Event-Version` header to retrieve a specific version's schema;\nwhen omitted, the event's latest version is returned.\n",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Epilot-Event-Version",
            "in": "header",
            "required": false,
            "description": "Event payload version (`MAJOR.MINOR`). Defaults to the event's latest version.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Event JSON Schema object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventJsonSchema"
                }
              }
            }
          },
          "404": {
            "description": "Event or version not found"
          }
        }
      }
    },
    "/v1/events/{event_name}/example": {
      "get": {
        "operationId": "getEventExample",
        "summary": "getEventExample",
        "description": "Generate a sample event payload based on the event's JSON Schema. Pass an\noptional `Epilot-Event-Version` header to generate the example for a\nspecific version; when omitted, the event's latest version is used.\n",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Epilot-Event-Version",
            "in": "header",
            "required": false,
            "description": "Event payload version (`MAJOR.MINOR`). Defaults to the event's latest version.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sample event payload object",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "A sample event payload generated from the JSON Schema"
                }
              }
            }
          },
          "404": {
            "description": "Event or version not found"
          }
        }
      }
    },
    "/v1/events/{event_name}/versions": {
      "get": {
        "operationId": "listEventVersions",
        "summary": "listEventVersions",
        "description": "List every known version of an event, along with the `latest`\nand the set of currently `active` versions. See §3.2 of the\nEvent Payload Versioning RFC.\n",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Registry summary for the event.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventVersionRegistrySummary"
                }
              }
            }
          },
          "404": {
            "description": "Event not found"
          }
        }
      }
    },
    "/v1/events/{event_name}:history": {
      "post": {
        "operationId": "searchEventHistory",
        "summary": "searchEventHistory",
        "description": "Paginated history of events",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchOptions"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List of events in the event history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "next_cursor": {
                      "type": "object",
                      "description": "Cursor for pagination. Use this to get the next page of results.",
                      "nullable": true,
                      "properties": {
                        "event_time": {
                          "type": "string",
                          "description": "Timestamp from the last event in the current page",
                          "example": "2025-10-31T12:34:56Z"
                        },
                        "event_id": {
                          "type": "string",
                          "description": "Event ID from the last event in the current page",
                          "example": "evt_1234567890abcdef"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/events/{event_name}:history": {
      "post": {
        "operationId": "searchEventHistoryV2",
        "summary": "searchEventHistoryV2",
        "description": "Paginated history of events with projected/lightweight payload (v2).\n\nReturns `EventSummary` objects instead of fully hydrated `Event` objects:\nhydrated entity objects (values carrying `_schema`/`_id`) are reduced to\nreference stubs `{_schema, _id, _title}` — the full entity is recoverable\nvia GET /v2/events/{event_name}/history/{event_id} or by hitting\nentity-api directly with the `_id`.\n",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchOptionsV2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List of event summaries in the event history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSummary"
                      }
                    },
                    "next_cursor": {
                      "type": "object",
                      "description": "Cursor for pagination. Use this to get the next page of results.",
                      "nullable": true,
                      "properties": {
                        "event_time": {
                          "type": "string",
                          "description": "Timestamp from the last event in the current page",
                          "example": "2025-10-31T12:34:56Z"
                        },
                        "event_id": {
                          "type": "string",
                          "description": "Event ID from the last event in the current page",
                          "example": "evt_1234567890abcdef"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v2/events/{event_name}/history/{event_id}": {
      "get": {
        "operationId": "getHistoricalEvent",
        "summary": "getHistoricalEvent",
        "description": "Fetch a single historical event by id with full hydration",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "description": "Unique event identifier (ULID)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The fully hydrated historical event",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Event"
                }
              }
            }
          },
          "404": {
            "description": "Event not found"
          }
        }
      }
    },
    "/v1/events/{event_name}:trigger": {
      "post": {
        "operationId": "triggerEvent",
        "summary": "triggerEvent",
        "description": "Explicitly trigger an event by providing input field values and an optional entity seed\nfor graph hydration. The event must be enabled for the organization.\n\n- For events with an entity_graph, a seed (entity_id + node_id) is required\n- For events without an entity_graph, only fields are needed\n- Entity operation context fields (operation, trigger_entity, activity_id, activity_type)\n  are not included when triggering via API\n",
        "tags": [
          "Event Catalog"
        ],
        "parameters": [
          {
            "name": "event_name",
            "in": "path",
            "required": true,
            "description": "Unique human readable name of the event",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TriggerEventPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event triggered successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TriggerEventResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input (validation error, missing seed, or missing required fields)"
          },
          "403": {
            "description": "Event is disabled for this organization"
          },
          "404": {
            "description": "Event not found"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "EpilotAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization header with epilot OAuth2 bearer token",
        "bearerFormat": "JWT"
      },
      "EpilotOrg": {
        "description": "Overrides the target organization to allow shared tenantaccess",
        "name": "x-epilot-org-id",
        "in": "header",
        "type": "apiKey"
      }
    },
    "schemas": {
      "EventConfigBase": {
        "type": "object",
        "description": "Base properties shared between EventConfig and UpdateEventPayload",
        "properties": {
          "event_name": {
            "type": "string",
            "description": "Unique human readable name of the event",
            "example": "AddMeterReading"
          },
          "event_title": {
            "type": "string",
            "description": "Human-friendly title for the event",
            "example": "Add Meter Reading"
          },
          "event_description": {
            "type": "string",
            "description": "Description of when the event is triggered",
            "example": "Triggered when a new meter reading is added"
          },
          "event_version": {
            "type": "string",
            "description": "Event payload version (MAJOR.MINOR)",
            "example": "1.0"
          },
          "event_status": {
            "type": "string",
            "description": "Status of the event",
            "enum": [
              "active",
              "deprecated",
              "draft",
              "disabled"
            ],
            "example": "active"
          },
          "event_tags": {
            "type": "array",
            "description": "Tags associated with the event for categorization and filtering\n\nThe \"builtin\" tag indicates events that are built into the epilot system.\n",
            "items": {
              "type": "string"
            },
            "example": [
              "builtin",
              "metering",
              "erp"
            ]
          },
          "schema_fields": {
            "type": "object",
            "description": "Fields that define the event schema",
            "additionalProperties": {
              "$ref": "#/components/schemas/SchemaField"
            }
          },
          "entity_graph": {
            "allOf": [
              {
                "$ref": "#/components/schemas/GraphDefinition"
              },
              {
                "description": "Optional entity graph definition for resolving related entities"
              }
            ]
          },
          "entity_operation": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntityOperationTrigger"
              },
              {
                "description": "Optional configuration for triggering this event based on entity operations"
              }
            ]
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether this event is enabled for the organization.\nWhen disabled, the event will not be triggered by any means\n(automatic, API, or automation).\nDefaults to true if not specified.\n",
            "default": true,
            "example": true
          },
          "auto_trigger": {
            "type": "boolean",
            "description": "Whether the event should be triggered automatically by built-in logic\n(e.g., portal submissions, entity mutations, EventBridge rules).\nWhen false, the event can still be triggered manually via API or automations.\nOnly meaningful for builtin events that have automatic trigger sources.\nDefaults to true if not specified.\n",
            "default": true,
            "example": true
          },
          "automation_trigger": {
            "type": "boolean",
            "description": "Whether this event can be explicitly triggered by automations.\nWhen true, the event will appear in the automation builder as a\n\"Trigger Event\" action option.\nDefaults to false if not specified.\n",
            "default": false,
            "example": true
          }
        }
      },
      "EventConfig": {
        "description": "Event configuration with required fields",
        "allOf": [
          {
            "$ref": "#/components/schemas/EventConfigBase"
          },
          {
            "type": "object",
            "required": [
              "event_name",
              "event_version",
              "schema_fields"
            ]
          }
        ]
      },
      "UpdateEventPayload": {
        "description": "Payload for updating an event configuration.\nAccepts the same fields as EventConfig (all optional for PATCH).\nCurrently `enabled` and `auto_trigger` fields are processed.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/EventConfigBase"
          },
          {
            "type": "object"
          }
        ]
      },
      "PrimitiveField": {
        "type": "object",
        "description": "A primitive JSON Schema field definition",
        "properties": {
          "json_schema": {
            "type": "object",
            "description": "JSON Schema definition of the field",
            "example": {
              "type": "string",
              "format": "date-time",
              "description": "ISO 8601 timestamp when reading was taken"
            }
          },
          "required": {
            "type": "boolean",
            "description": "Whether this field is required in the event payload"
          },
          "graph_source": {
            "type": "string",
            "description": "Optional JSONata expression to extract the field value from the hydrated entity graph.\n\nThe expression has access to all hydrated graph nodes by their node ID.\nIf not specified, the field value must be provided as input when triggering the event.\n\nExamples:\n  - \"ticket.meter_reading_value\" (simple path)\n  - \"contact.email[0].email\" (nested/array access)\n  - \"ticket.reading_timestamp ?? $now()\" (with fallback)\n  - \"$number(meter_counter.reading_value)\" (type coercion)\n",
            "example": "ticket.meter_reading_value"
          }
        },
        "required": [
          "json_schema"
        ]
      },
      "ContextEntity": {
        "type": "object",
        "properties": {
          "entity_schema": {
            "type": "string",
            "example": "meter",
            "description": "Schema slug of the context entity"
          },
          "required": {
            "type": "boolean",
            "description": "Whether this field is required in the event payload"
          }
        },
        "required": [
          "entity_schema"
        ]
      },
      "AttachmentField": {
        "type": "object",
        "description": "A schema field representing file attachments associated with the event.\nPresent in schema_fields for events tagged with \"attachment\".\n",
        "properties": {
          "items": {
            "$ref": "#/components/schemas/EventAttachment"
          },
          "required": {
            "type": "boolean",
            "description": "Whether this field is required in the event payload"
          }
        },
        "required": [
          "items"
        ]
      },
      "SchemaField": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/PrimitiveField"
          },
          {
            "$ref": "#/components/schemas/ContextEntity"
          },
          {
            "$ref": "#/components/schemas/AttachmentField"
          }
        ]
      },
      "CommonEventMetadata": {
        "type": "object",
        "description": "Common metadata fields present in all event payloads",
        "example": {
          "_org_id": {
            "type": "string",
            "description": "epilot tenant/organization ID"
          },
          "_event_time": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp when event occurred"
          },
          "_event_id": {
            "type": "string",
            "description": "Unique event identifier (ULID)"
          },
          "_event_name": {
            "type": "string",
            "description": "Event name from catalog"
          },
          "_event_version": {
            "type": "string",
            "description": "Schema version number"
          },
          "_event_source": {
            "type": "string",
            "description": "Source that triggered the event"
          },
          "_ack_id": {
            "type": "string",
            "description": "Unique acknowledgment tracking ID for the event"
          }
        },
        "required": [
          "_org_id",
          "_event_time",
          "_event_id",
          "_event_name",
          "_event_version",
          "_event_source"
        ]
      },
      "EventJsonSchema": {
        "type": "object",
        "description": "JSON Schema declaring the event payload structure",
        "example": {
          "type": "object",
          "properties": {
            "_org_id": {
              "type": "string",
              "description": "epilot tenant/organization ID"
            },
            "_event_time": {
              "type": "string",
              "format": "date-time",
              "description": "ISO 8601 timestamp when event occurred"
            },
            "_event_id": {
              "type": "string",
              "description": "Unique event identifier (ULID)"
            },
            "_event_name": {
              "type": "string",
              "description": "Event name from catalog"
            },
            "_event_version": {
              "type": "string",
              "description": "Event payload version (MAJOR.MINOR)"
            },
            "_event_source": {
              "type": "string",
              "description": "Source that triggered the event"
            },
            "reading_value": {
              "type": "number",
              "description": "The meter reading value"
            },
            "reading_date": {
              "type": "string",
              "format": "date-time",
              "description": "ISO 8601 timestamp when reading was taken"
            },
            "read_by": {
              "type": "string",
              "description": "Name or identifier of who submitted the reading"
            },
            "reason": {
              "type": "string",
              "enum": [
                "regular",
                "move-in",
                "move-out",
                "supplier-change",
                "correction",
                "final"
              ],
              "description": "Reason for the meter reading"
            },
            "direction": {
              "type": "string",
              "enum": [
                "feed-in",
                "feed-out"
              ],
              "description": "Direction of energy flow"
            },
            "source": {
              "type": "string",
              "enum": [
                "portal",
                "360",
                "api",
                "automation"
              ],
              "description": "Source system where reading was submitted"
            },
            "meter_id": {
              "type": "string",
              "format": "uuid",
              "description": "Entity ID of the meter"
            },
            "counter_id": {
              "type": "string",
              "format": "uuid",
              "description": "Entity ID of the meter counter"
            },
            "meter_number": {
              "type": "string",
              "description": "Human-readable meter number"
            },
            "obis_number": {
              "type": "string",
              "description": "OBIS code of the counter"
            },
            "unit": {
              "type": "string",
              "description": "Unit of measurement (e.g., kWh, m3)"
            },
            "customer_id": {
              "type": "string",
              "format": "uuid",
              "description": "Entity ID of the customer"
            },
            "contract_id": {
              "type": "string",
              "format": "uuid",
              "description": "Entity ID of the contract"
            },
            "user_id": {
              "type": "string",
              "description": "ID of the user who submitted the reading"
            },
            "user_email": {
              "type": "string",
              "format": "email",
              "description": "Email of the user who submitted the reading"
            }
          },
          "required": [
            "_org_id",
            "_event_time",
            "_event_id",
            "_event_name",
            "_event_version",
            "_event_source",
            "reading_value",
            "reading_date",
            "read_by",
            "reason",
            "direction",
            "source",
            "meter_id",
            "counter_id",
            "meter_number",
            "obis_number",
            "unit",
            "customer_id",
            "contract_id"
          ]
        }
      },
      "Event": {
        "type": "object",
        "description": "An event instance in the event history",
        "properties": {
          "_org_id": {
            "type": "string",
            "description": "epilot tenant/organization ID"
          },
          "_event_time": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp when event occurred"
          },
          "_event_id": {
            "type": "string",
            "description": "Unique event identifier (ULID)"
          },
          "_event_name": {
            "type": "string",
            "description": "Event name from catalog"
          },
          "_event_version": {
            "type": "string",
            "description": "Event payload version (MAJOR.MINOR)",
            "example": "1.0"
          },
          "_event_source": {
            "type": "string",
            "description": "Source that triggered the event"
          },
          "_trigger_source_type": {
            "type": "string",
            "description": "The type of system that triggered the event.\nCommon values: api, automation, operation, portal_user\n",
            "example": "api"
          },
          "_trigger_source": {
            "type": "string",
            "description": "Identifier of the specific trigger source.\n- For api: User ID or API key identifier\n- For automation: Automation execution ID\n- For operation: Activity ID from the entity operation\n- For portal_user: Portal user email\n"
          },
          "_ack_id": {
            "type": "string",
            "description": "Unique acknowledgment tracking ID for the event.\nUsed to track event delivery and processing status.\n"
          }
        },
        "required": [
          "_org_id",
          "_event_time",
          "_event_id",
          "_event_name",
          "_event_version",
          "_event_source"
        ],
        "additionalProperties": true,
        "example": {
          "_org_id": "org_123456",
          "_event_time": "2024-01-01T12:00:00Z",
          "_event_id": "01FZ4Z5FZ5FZ5FZ5FZ5FZ5FZ5F",
          "_event_name": "MeterReading",
          "_event_version": "1.0",
          "_event_source": "api",
          "_trigger_source_type": "api",
          "_trigger_source": "user_123456",
          "reading_value": 123.45,
          "reading_date": "2024-01-01T11:59:00Z",
          "read_by": "John Doe",
          "reason": "regular",
          "direction": "feed-out",
          "source": "portal",
          "meter_id": "550e8400-e29b-41d4-a716-446655440000",
          "counter_id": "660e8400-e29b-41d4-a716-446655440000",
          "meter_number": "MT123456789",
          "obis_number": "1-0:1.8.0",
          "unit": "kWh",
          "customer_id": "770e8400-e29b-41d4-a716-446655440000",
          "contract_id": "880e8400-e29b-41d4-a716-446655440000"
        }
      },
      "EventSummary": {
        "type": "object",
        "description": "A lightweight event summary returned by the v2 history endpoint.\n\nIncludes the standard `_*` metadata fields plus a projected subset of the\nevent payload. Hydrated entity objects (values carrying `_schema` or `_id`)\n— and arrays of such objects — are reduced to reference stubs\n`{_schema, _id, _title}` so consumers can identify and follow up on each\nentity without paying the cost of the full hydrated graph. Fetch\n`GET /v2/events/{event_name}/history/{event_id}` for the full hydration.\n\nProjected scalar payload fields appear as additional top-level properties.\n",
        "properties": {
          "_org_id": {
            "type": "string",
            "description": "epilot tenant/organization ID"
          },
          "_event_time": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp when event occurred"
          },
          "_event_id": {
            "type": "string",
            "description": "Unique event identifier (ULID)"
          },
          "_event_name": {
            "type": "string",
            "description": "Event name from catalog"
          },
          "_event_version": {
            "type": "string",
            "description": "Event payload version (MAJOR.MINOR)",
            "example": "1.0"
          },
          "_event_source": {
            "type": "string",
            "description": "Source that triggered the event"
          },
          "_trigger_source_type": {
            "type": "string",
            "description": "The type of system that triggered the event.\nCommon values: api, automation, operation, portal_user\n",
            "example": "api"
          },
          "_trigger_source": {
            "type": "string",
            "description": "Identifier of the specific trigger source.\n"
          },
          "_ack_id": {
            "type": "string",
            "description": "Unique acknowledgment tracking ID for the event.\n"
          }
        },
        "required": [
          "_org_id",
          "_event_time",
          "_event_id",
          "_event_name",
          "_event_version",
          "_event_source"
        ],
        "additionalProperties": true
      },
      "GraphDefinition": {
        "type": "object",
        "description": "Entity graph definition for resolving related entities",
        "properties": {
          "nodes": {
            "type": "array",
            "description": "List of node definitions in the graph",
            "items": {
              "$ref": "#/components/schemas/GraphNode"
            }
          },
          "edges": {
            "type": "array",
            "description": "List of edge definitions connecting nodes",
            "items": {
              "$ref": "#/components/schemas/GraphEdge"
            }
          }
        },
        "required": [
          "nodes",
          "edges"
        ]
      },
      "GraphNode": {
        "type": "object",
        "description": "A node in the entity graph",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this node in the graph definition",
            "example": "contact"
          },
          "schema": {
            "type": "string",
            "description": "Entity schema slug for this node",
            "example": "contact"
          },
          "cardinality": {
            "type": "string",
            "enum": [
              "one",
              "many"
            ],
            "description": "Cardinality for this node when hydrated:\n- \"one\": Node can only contain one entity, returns single Entity object\n- \"many\": Node can contain multiple entities, returns array of Entity objects\nIf not specified, defaults to \"many\" (returns array)\n",
            "example": "one"
          },
          "fields": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FieldsParam"
              },
              {
                "description": "Optional array of field names to include in the hydrated entity response for this node.\nWhen specified, only the requested fields plus required internal fields (_id, _schema, _org) will be returned.\nOnly applies when hydrate=true.\n"
              }
            ]
          }
        },
        "required": [
          "id",
          "schema"
        ]
      },
      "GraphEdge": {
        "type": "object",
        "description": "An edge connecting two nodes in the graph",
        "properties": {
          "from": {
            "type": "string",
            "description": "Source node ID",
            "example": "contact"
          },
          "to": {
            "type": "string",
            "description": "Target node ID",
            "example": "billing_account"
          }
        },
        "required": [
          "from",
          "to"
        ]
      },
      "EntityOperationTrigger": {
        "type": "object",
        "description": "Configuration for triggering an event based on entity operations.\n\nWhen an entity operation matches the configured criteria, the event will be triggered.\n- On createEntity: the attribute must be present in the entity payload\n- On updateEntity: the attribute must be in diff.added, diff.updated, or diff.deleted\n- On deleteEntity: the event triggers when the entity is deleted (attributes not checked)\n",
        "properties": {
          "operation": {
            "type": "array",
            "description": "List of entity operations that can trigger this event",
            "items": {
              "type": "string",
              "enum": [
                "createEntity",
                "updateEntity",
                "deleteEntity"
              ]
            },
            "example": [
              "createEntity",
              "updateEntity"
            ]
          },
          "schema": {
            "type": "array",
            "description": "List of entity schema slugs that can trigger this event",
            "items": {
              "type": "string"
            },
            "example": [
              "contact",
              "contract",
              "order"
            ]
          },
          "attribute": {
            "type": "array",
            "description": "Optional list of entity attributes to track for changes.\nIf specified, the event only triggers when these attributes are affected.\n- On createEntity: attribute must be defined in the entity payload\n- On updateEntity: attribute must be in diff.added, diff.updated, or diff.deleted\nIf not specified, all changes to matching entities will trigger the event.\n",
            "items": {
              "type": "string"
            },
            "example": [
              "email",
              "phone",
              "status"
            ]
          },
          "purpose": {
            "type": "array",
            "description": "Optional list of purpose names to filter by.\nThe entity must have at least one matching purpose in its _purpose array.\nPurpose names are matched against the taxonomy classification names (e.g., \"Kündigung\", \"Umzug/Auszug\").\nIf not specified, the event triggers regardless of entity purpose.\n",
            "items": {
              "type": "string"
            },
            "example": [
              "Kündigung",
              "Umzug/Auszug"
            ]
          }
        },
        "required": [
          "operation",
          "schema"
        ]
      },
      "SearchOptions": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "description": "Maximum number of results to return",
            "default": 10,
            "minimum": 1,
            "maximum": 25
          },
          "cursor": {
            "type": "object",
            "description": "Cursor for pagination. Use the next_cursor from the previous response to get the next page.",
            "properties": {
              "event_time": {
                "type": "string",
                "description": "Timestamp from the last event in the previous page",
                "example": "2025-10-31 12:34:56"
              },
              "event_id": {
                "type": "string",
                "description": "Event ID from the last event in the previous page",
                "example": "evt_1234567890abcdef"
              }
            }
          },
          "timestamp": {
            "type": "object",
            "description": "Filter events by timestamp range",
            "properties": {
              "from": {
                "type": "string",
                "format": "date-time",
                "description": "Start timestamp in ISO 8601 format",
                "example": "2025-10-01T00:00:00Z"
              },
              "to": {
                "type": "string",
                "format": "date-time",
                "description": "End timestamp in ISO 8601 format",
                "example": "2025-10-31T23:59:59Z"
              }
            }
          },
          "event_id": {
            "type": "string",
            "description": "Filter by specific event ID",
            "example": "evt_1234567890abcdef"
          }
        }
      },
      "SearchOptionsV2": {
        "description": "Search options for the v2 history endpoint.\n\nExtends `SearchOptions` with an optional `fields` projection. When `fields`\nis omitted, the response includes all `_*` metadata plus all scalar payload\nfields (and primitive arrays / empty objects/arrays) after entity stripping.\nWhen `fields` is provided, glob/exclusion semantics from `FieldsParam` apply\nagainst `payload.*` paths; `_*` metadata is always included. Entity stripping\nruns AFTER selection.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/SearchOptions"
          },
          {
            "type": "object",
            "properties": {
              "fields": {
                "$ref": "#/components/schemas/FieldsParam"
              }
            }
          }
        ]
      },
      "FieldsParam": {
        "type": "array",
        "description": "List of entity fields to include or exclude in the response\n\nUse ! to exclude fields, e.g. `!_id` to exclude the `_id` field.\n\nGlobbing and globstart (**) is supported for nested fields.\n",
        "items": {
          "type": "string"
        },
        "example": [
          "_id",
          "_title",
          "first_name",
          "account",
          "!account.*._files",
          "**._product"
        ]
      },
      "TriggerEventPayload": {
        "type": "object",
        "description": "Payload for explicitly triggering an event via API",
        "properties": {
          "seed": {
            "type": "object",
            "description": "Entity seed for graph hydration. Required for events that have an entity_graph defined.\nSpecifies which entity to start graph traversal from.\n",
            "properties": {
              "entity_id": {
                "type": "string",
                "format": "uuid",
                "description": "Entity ID to seed the graph hydration"
              },
              "node_id": {
                "type": "string",
                "description": "Node ID from the event's entity_graph definition that matches\nthe seed entity. Must be a valid node in the event's graph.\n"
              }
            },
            "required": [
              "entity_id",
              "node_id"
            ]
          },
          "fields": {
            "type": "object",
            "description": "Input field values for the event. Keys must match the event's\nschema_fields definitions. Values are validated against each\nfield's JSON Schema.\n",
            "additionalProperties": true
          },
          "skip_hydration": {
            "type": "array",
            "description": "Optional list of node IDs to skip during entity graph hydration.\nThese nodes will be null/undefined in the event payload.\n",
            "items": {
              "type": "string"
            }
          },
          "_trigger_source_type": {
            "type": "string",
            "description": "The type of system that triggered the event.\nExamples: api, automation, operation, portal_user\nDefaults to \"api\" if not specified.\n"
          },
          "_trigger_source": {
            "type": "string",
            "description": "Identifier of the specific trigger source.\nExamples: user ID, automation execution ID, activity ID, portal user email\nDefaults to the calling user ID if not specified.\n"
          }
        }
      },
      "TriggerEventResponse": {
        "type": "object",
        "description": "Response from triggering an event",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the event was triggered successfully"
          },
          "event_id": {
            "type": "string",
            "description": "The unique event ID (ULID) assigned to this event"
          },
          "event_bridge_event_id": {
            "type": "string",
            "description": "EventBridge event ID from publishing"
          }
        },
        "required": [
          "success",
          "event_id"
        ]
      },
      "EventAttachment": {
        "type": "object",
        "description": "A file attachment associated with an event",
        "properties": {
          "entity_id": {
            "type": "string",
            "format": "uuid",
            "description": "Entity ID of the file"
          },
          "filename": {
            "type": "string",
            "description": "Name of the file"
          },
          "mime_type": {
            "type": "string",
            "description": "MIME type of the file (e.g., application/pdf)"
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0,
            "description": "File size in bytes"
          },
          "s3ref": {
            "type": "object",
            "description": "S3 reference for the file content",
            "properties": {
              "bucket": {
                "type": "string",
                "description": "S3 bucket name"
              },
              "key": {
                "type": "string",
                "description": "S3 object key"
              }
            },
            "required": [
              "bucket",
              "key"
            ]
          },
          "version_index": {
            "type": "integer",
            "description": "File version index (always 0 for newly created files)"
          },
          "readable_size": {
            "type": "string",
            "description": "Human-readable file size (e.g., \"200 KB\")"
          }
        },
        "required": [
          "entity_id",
          "version_index"
        ]
      },
      "FieldChange": {
        "type": "object",
        "description": "A field-level change descriptor. Powers the declarative half of the\nversion DSL.\n",
        "properties": {
          "field": {
            "type": "string",
            "description": "Name of the field affected by this change.",
            "example": "reading"
          },
          "op": {
            "type": "string",
            "enum": [
              "added",
              "removed",
              "type-changed"
            ],
            "description": "Kind of change. Renames are NOT a first-class op — represent them\nas a `removed` + `added` pair (semantic intent goes into\n`change_summary` / `change_notes`).\n"
          },
          "type_old": {
            "type": "string",
            "description": "Type label for the previous shape (for `removed` and `type-changed`)."
          },
          "type_new": {
            "type": "string",
            "description": "Type label for the new shape (for `added` and `type-changed`)."
          }
        },
        "required": [
          "field",
          "op"
        ]
      },
      "VersionMeta": {
        "type": "object",
        "description": "One entry of an event's version timeline.",
        "properties": {
          "version": {
            "type": "string",
            "description": "MAJOR.MINOR version label.",
            "example": "1.0"
          },
          "released_at": {
            "type": "string",
            "description": "ISO 8601 release timestamp.",
            "example": "2025-11-15"
          },
          "change_summary": {
            "type": "string",
            "description": "Required one-liner describing what changed in this version (≤280 chars)."
          },
          "change_notes": {
            "type": "string",
            "description": "Optional longer-form prose (markdown)."
          },
          "changes": {
            "type": "array",
            "description": "Hand-authored list of field-level changes from the previous version. Empty for v1.",
            "items": {
              "$ref": "#/components/schemas/FieldChange"
            }
          }
        },
        "required": [
          "version",
          "released_at",
          "change_summary",
          "changes"
        ]
      },
      "EventVersionRegistrySummary": {
        "type": "object",
        "description": "Summary of an event's version timeline returned by\n`GET /v1/events/{event_name}/versions`.\n",
        "properties": {
          "event_name": {
            "type": "string",
            "example": "MeterReadingAdded"
          },
          "latest": {
            "type": "string",
            "description": "The newest registered version.",
            "example": "1.0"
          },
          "versions": {
            "type": "array",
            "description": "Full version timeline, ordered oldest → newest.",
            "items": {
              "$ref": "#/components/schemas/VersionMeta"
            }
          }
        },
        "required": [
          "event_name",
          "latest",
          "versions"
        ]
      }
    }
  },
  "servers": [
    {
      "url": "https://event-catalog.sls.epilot.io"
    }
  ]
}
