{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/shelfatlas-com/json-schema/shelfatlas-com-offer-history-summary-schema.json",
  "title": "OfferHistorySummary",
  "description": "Context derived from the CAMPAIGN rows of the series. These are advertised leaflet prices — never present them as a normal or shelf price.",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/shelfatlas-com-openapi.json#/components/schemas/OfferHistorySummary",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "lowest_cents",
    "median_cents",
    "chains",
    "weeks_seen",
    "offer_pattern"
  ],
  "properties": {
    "lowest_cents": {
      "type": "integer"
    },
    "median_cents": {
      "type": "integer"
    },
    "chains": {
      "type": "integer",
      "description": "Distinct chains that advertised the item."
    },
    "weeks_seen": {
      "type": "integer",
      "description": "Distinct ISO weeks in which the item was advertised."
    },
    "offer_pattern": {
      "type": [
        "object",
        "null"
      ],
      "additionalProperties": false,
      "required": [
        "share_of_days_on_offer",
        "days_on_offer",
        "days_total",
        "periods",
        "typical_duration_days",
        "typical_gap_days",
        "on_offer_now",
        "days_since_last_offer",
        "next_expected_in_days"
      ],
      "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 84 days. History coverage starts 2026-04-13, so a 365-day window is diluted until April 2027 — ask for 180 days to get a pattern. The figures are medians of the past, not a forecast.",
      "properties": {
        "share_of_days_on_offer": {
          "type": "number",
          "description": "Share of the window's days on offer (0–1, 2 decimals)."
        },
        "days_on_offer": {
          "type": "integer",
          "description": "Days inside an offer period."
        },
        "days_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 day without an offer separates two."
        },
        "typical_duration_days": {
          "type": "number",
          "description": "Median length of an offer period, in days (1 decimal)."
        },
        "typical_gap_days": {
          "type": "number",
          "description": "Median days WITHOUT an offer between two consecutive periods (1 decimal)."
        },
        "on_offer_now": {
          "type": "boolean",
          "description": "True when the window's last day is inside an offer period."
        },
        "days_since_last_offer": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Days since the last offer period ended; null while on_offer_now."
        },
        "next_expected_in_days": {
          "type": [
            "integer",
            "null"
          ],
          "description": "If the pattern holds: typical gap minus days since the last offer, floored at 0 (0 = due now). Null while on_offer_now."
        }
      }
    }
  }
}