{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/shelfatlas-com/json-schema/shelfatlas-com-term-history-summary-schema.json",
  "title": "TermHistorySummary",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/shelfatlas-com-openapi.json#/components/schemas/TermHistorySummary",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "weeks_total",
    "weeks_with_offers",
    "typical_price",
    "lowest_price",
    "lowest_price_week_start",
    "lowest_price_chain_name",
    "weeks_on_offer_last_8",
    "unit",
    "weeks_with_unit_price",
    "typical_unit_price",
    "lowest_unit_price",
    "lowest_unit_price_week_start",
    "lowest_unit_price_chain_name",
    "offer_pattern"
  ],
  "properties": {
    "weeks_total": {
      "type": "integer",
      "description": "Number of weeks in the requested window."
    },
    "weeks_with_offers": {
      "type": "integer",
      "description": "Of weeks_total, how many had at least one matching offer."
    },
    "typical_price": {
      "type": [
        "number",
        "null"
      ],
      "description": "Median of the weekly min_price over weeks with offers, 2 decimals. Shelf prices across pack sizes — prefer typical_unit_price for a \"typical price\" claim."
    },
    "lowest_price": {
      "type": [
        "number",
        "null"
      ],
      "description": "The smallest weekly min_price in the window."
    },
    "lowest_price_week_start": {
      "type": [
        "string",
        "null"
      ],
      "format": "date"
    },
    "lowest_price_chain_name": {
      "type": [
        "string",
        "null"
      ]
    },
    "weeks_on_offer_last_8": {
      "type": "integer",
      "description": "Of the LAST 8 weeks, how many had at least one campaign offer."
    },
    "unit": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "l",
        "kg",
        "stk",
        null
      ],
      "description": "SA-0230: the unit the window compares on — the one most offers carry (ties l > kg > stk). Null when no offer has a usable unit price; every *_unit_price field is then null."
    },
    "weeks_with_unit_price": {
      "type": "integer",
      "description": "Weeks with a cheapest_unit_price."
    },
    "typical_unit_price": {
      "type": [
        "number",
        "null"
      ],
      "description": "Median of the weekly cheapest_unit_price (DKK per unit), 2 decimals. The like-for-like \"typical price\"."
    },
    "lowest_unit_price": {
      "type": [
        "number",
        "null"
      ],
      "description": "The smallest weekly cheapest_unit_price (DKK per unit)."
    },
    "lowest_unit_price_week_start": {
      "type": [
        "string",
        "null"
      ],
      "format": "date"
    },
    "lowest_unit_price_chain_name": {
      "type": [
        "string",
        "null"
      ]
    },
    "offer_pattern": {
      "type": [
        "object",
        "null"
      ],
      "additionalProperties": false,
      "required": [
        "share_of_weeks_on_offer",
        "weeks_on_offer",
        "weeks_total",
        "periods",
        "typical_duration_weeks",
        "typical_gap_weeks",
        "on_offer_now",
        "weeks_since_last_offer",
        "next_expected_in_weeks"
      ],
      "description": "How often, how long and how far apart the offers come, from our own CAMPAIGN history (a regular shelf price never counts as an offer). null unless there are at least 3 offer periods in a window of at least 12 weeks. A weeks=8 request therefore always returns null. The figures are medians of the past, not a forecast.",
      "properties": {
        "share_of_weeks_on_offer": {
          "type": "number",
          "description": "Share of the window's weeks on offer (0–1, 2 decimals)."
        },
        "weeks_on_offer": {
          "type": "integer",
          "description": "Weeks inside an offer period."
        },
        "weeks_total": {
          "type": "integer",
          "description": "Length of the window asked for (not of the data we hold)."
        },
        "periods": {
          "type": "integer",
          "description": "Distinct offer periods. Periods that overlap or touch are one; a single week without an offer separates two."
        },
        "typical_duration_weeks": {
          "type": "number",
          "description": "Median length of an offer period, in weeks (1 decimal)."
        },
        "typical_gap_weeks": {
          "type": "number",
          "description": "Median weeks WITHOUT an offer between two consecutive periods (1 decimal)."
        },
        "on_offer_now": {
          "type": "boolean",
          "description": "True when the window's last week is inside an offer period."
        },
        "weeks_since_last_offer": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Weeks since the last offer period ended; null while on_offer_now."
        },
        "next_expected_in_weeks": {
          "type": [
            "integer",
            "null"
          ],
          "description": "If the pattern holds: typical gap minus weeks since the last offer, floored at 0 (0 = due now). Null while on_offer_now."
        }
      }
    }
  }
}