{
  "title": "WooCommerce catalogs and changes — settings",
  "type": "object",
  "schemaVersion": 1,
  "properties": {
    "storeUrls": {
      "title": "Public WooCommerce store base URLs",
      "type": "array",
      "description": "Up to 20 public WooCommerce store base URLs, optionally including a WordPress installation subdirectory. Empty or omitted uses WordPress Mercantile. The public Store API must be enabled and robots.txt must permit access.",
      "editor": "stringList",
      "prefill": [
        "https://mercantile.wordpress.org"
      ],
      "sectionCaption": "Store URLs and catalog scope"
    },
    "mode": {
      "title": "Catalog export or saved comparison",
      "type": "string",
      "description": "Catalog exports current products without changing saved baselines. Changes compares with a named baseline; its first run emits initial products labeled baseline. Only complete crawls advance a baseline. Omitted mode means catalog.",
      "enum": [
        "catalog",
        "changes"
      ],
      "enumTitles": [
        "Current catalog",
        "Changes since last complete run"
      ],
      "editor": "select"
    },
    "maxProductsPerStore": {
      "title": "Maximum observed products per store",
      "type": "integer",
      "description": "Hard cap on observed current products per store. A run that hits this cap before the full source scope is read preserves the old baseline and suppresses removals. Removed-product events may add rows beyond this cap in changes mode.",
      "default": 50,
      "minimum": 1,
      "maximum": 5000
    },
    "maxPagesPerStore": {
      "title": "Maximum catalog pages per store",
      "type": "integer",
      "description": "Pagination safety limit. Pages contain up to 100 products. Reaching the limit before the complete catalog preserves the saved baseline.",
      "default": 100,
      "minimum": 1,
      "maximum": 100
    },
    "search": {
      "title": "Product search",
      "type": "string",
      "description": "Optional public Store API product search, up to 200 characters. Changing the search selects a separate baseline scope.",
      "editor": "textfield"
    },
    "categoryIds": {
      "title": "Store-specific category IDs",
      "type": "array",
      "description": "Optional store-specific positive integer category IDs. These are category IDs from product output, not category names. Up to 50 values; changing them selects a separate baseline scope.",
      "items": {
        "type": "integer",
        "minimum": 1
      },
      "editor": "json"
    },
    "onSale": {
      "title": "Only products on sale",
      "type": "boolean",
      "description": "When true, request only sale products. False or omitted includes both sale and regular products. Leaving this filtered scope does not prove that a product was deleted.",
      "default": false
    },
    "stockStatus": {
      "title": "Availability filter",
      "type": "string",
      "description": "Limit the source scope to a public stock status, or include all. Filters affect scope membership; removed_from_scope means absent from this scope, not necessarily deleted from the store.",
      "enum": [
        "any",
        "instock",
        "outofstock",
        "onbackorder"
      ],
      "enumTitles": [
        "All products",
        "In stock",
        "Out of stock",
        "On backorder"
      ],
      "editor": "select",
      "default": "any"
    },
    "minimumPriceChangePercent": {
      "title": "Current-price change threshold (%)",
      "type": "number",
      "description": "Only emit a price_changed label when the current price moves by at least this percentage from the previous complete snapshot. Other changes can still emit the product. A move from zero always qualifies. The baseline advances even for changes below this threshold.",
      "default": 0,
      "minimum": 0,
      "maximum": 100000
    },
    "baselineKey": {
      "title": "Comparison history name",
      "type": "string",
      "description": "Changes mode only. Use 1-80 letters, digits, underscores or hyphens to isolate independent monitors. Store URL and filters are also included automatically. First use emits all initial products. Avoid overlapping runs using the same key and scope.",
      "editor": "textfield",
      "default": "default"
    },
    "maxRunSeconds": {
      "title": "Run time budget (seconds)",
      "type": "integer",
      "description": "Own wall-clock budget, also bounded by the platform timeout with a safety margin. Requests and retry sleeps share this budget. Partial catalogs never replace a baseline.",
      "default": 240,
      "minimum": 30,
      "maximum": 3600,
      "sectionCaption": "Run budget"
    }
  },
  "description": "For assortment research and availability monitoring, export public WooCommerce products or compare them with a complete saved catalog scope. Stores exposing the public WooCommerce Store API and permitting access. No customer, order or private inventory data."
}
