{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/robosystems-ai/json-schema/robosystems-ai-create-event-handler-request-schema.json",
  "title": "CreateEventHandlerRequest",
  "description": "Register a new event-type → transaction-template rule.\n\nWhen `create-event-block` runs with `apply_handlers=True`, the\nregistry resolves the *highest-priority active* handler whose match\ncriteria all match the event, then evaluates the\n`transaction_template` to produce GL rows. Match precedence: among\nactive handlers for the same `event_type`, the one with the most\nspecific match (more match fields satisfied) wins; ties broken by\n`priority` desc, then `created_at` asc.\n\nAll match fields except `event_type` are optional — leaving them\nunset matches anything. Use `match_metadata_expression` for\nfine-grained discrimination (e.g. only payroll categories).",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/robosystems-ai-openapi.json#/components/schemas/CreateEventHandlerRequest",
  "properties": {
    "name": {
      "type": "string",
      "title": "Name",
      "description": "Human-readable handler name (unique per graph)."
    },
    "description": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Description",
      "description": "Free-form description shown in admin UIs."
    },
    "event_type": {
      "type": "string",
      "title": "Event Type",
      "description": "Event type to match. Matches the `event_type` field on incoming events from `create-event-block`."
    },
    "event_category": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Event Category",
      "description": "Optional category filter (e.g. 'expense', 'revenue')."
    },
    "match_source": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Match Source",
      "description": "Match the event's `source` field (e.g. 'quickbooks', 'plaid'). Useful when the same event_type comes from multiple integrations."
    },
    "match_agent_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Match Agent Type",
      "description": "Match agent-emitted events by agent_type."
    },
    "match_resource_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Match Resource Type",
      "description": "Match resource-bound events by resource_type."
    },
    "match_metadata_expression": {
      "anyOf": [
        {
          "additionalProperties": true,
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "title": "Match Metadata Expression",
      "description": "JSONPath-style equality map against event.metadata, e.g. {\"category\": \"payroll\"} or {\"metadata.category\": \"payroll\"}"
    },
    "transaction_template": {
      "$ref": "#/$defs/TransactionTemplate",
      "description": "The DSL spec for the GL rows this handler produces. See `TransactionTemplate` for the shape."
    },
    "priority": {
      "type": "integer",
      "title": "Priority",
      "description": "Tiebreaker when multiple equally-specific handlers match. Higher = wins.",
      "default": 0
    },
    "is_active": {
      "type": "boolean",
      "title": "Is Active",
      "description": "Inactive handlers are ignored at match time.",
      "default": true
    },
    "origin": {
      "type": "string",
      "enum": [
        "hub",
        "tenant"
      ],
      "title": "Origin",
      "description": "Provenance of the handler. `tenant` = authored on this graph, the only value a caller may set; `hub` = platform-shipped template.",
      "default": "tenant"
    },
    "metadata": {
      "additionalProperties": true,
      "type": "object",
      "title": "Metadata",
      "description": "Free-form metadata stored alongside the handler."
    }
  },
  "type": "object",
  "required": [
    "name",
    "event_type",
    "transaction_template"
  ],
  "$defs": {
    "TransactionTemplate": {
      "properties": {
        "transactions": {
          "items": {
            "$ref": "#/$defs/TransactionTemplateItem"
          },
          "type": "array",
          "minItems": 1,
          "title": "Transactions",
          "description": "At least one debit/credit entry pair"
        }
      },
      "type": "object",
      "required": [
        "transactions"
      ],
      "title": "TransactionTemplate",
      "description": "The handler's output spec — one or more balanced entries to post.\n\nWire shape::\n\n    {\n      \"transactions\": [{\n        \"entry_template\": {\n          \"debit\": {\"element_id\": \"elem_...\", \"amount\": \"{{ event.amount }}\"},\n          \"credit\": {\"element_id\": \"elem_...\", \"amount\": \"{{ event.amount }}\"}\n        }\n      }]\n    }"
    },
    "TransactionTemplateEntry": {
      "properties": {
        "debit": {
          "$ref": "#/$defs/TransactionTemplateLeg"
        },
        "credit": {
          "$ref": "#/$defs/TransactionTemplateLeg"
        }
      },
      "type": "object",
      "required": [
        "debit",
        "credit"
      ],
      "title": "TransactionTemplateEntry",
      "description": "One balanced entry (debit + credit pair) — the inner shape of entry_template."
    },
    "TransactionTemplateItem": {
      "properties": {
        "entry_template": {
          "$ref": "#/$defs/TransactionTemplateEntry"
        }
      },
      "type": "object",
      "required": [
        "entry_template"
      ],
      "title": "TransactionTemplateItem",
      "description": "One item in the transactions list — wraps entry_template to match the DSL shape."
    },
    "TransactionTemplateLeg": {
      "properties": {
        "element_id": {
          "type": "string",
          "title": "Element Id",
          "description": "Element ULID (elem_ prefixed) identifying the account to post to"
        },
        "amount": {
          "type": "string",
          "title": "Amount",
          "description": "Amount expression. Supports: '{{ event.amount }}' — raw event amount (cents); '{{ event.amount }} / 2' — half of event amount; '{{ event.metadata.fee_cents }}' — field from event metadata"
        }
      },
      "type": "object",
      "required": [
        "element_id",
        "amount"
      ],
      "title": "TransactionTemplateLeg",
      "description": "One side of a journal entry leg (debit or credit)."
    }
  }
}