{
  "schemaVersion": "1.0.0",
  "datasetId": "us-retail-lvp-field-dictionary",
  "name": "Observed US online retail prices for hard-surface flooring — field dictionary",
  "describes": [
    "https://floorcostestimator.com/data/price-band-v1.json",
    "https://floorcostestimator.com/data/history.json"
  ],
  "describesSchemaVersion": "1.1.0",
  "dataAsOf": "2026-08-19",
  "url": "https://floorcostestimator.com/cost-data",
  "license": "https://creativecommons.org/licenses/by/4.0/",
  "citation": "Floor Cost Estimator, \"Observed US online retail prices for hard-surface flooring\", observed August 19, 2026. Published by a materials-only flooring retailer that sells the category it prices. https://floorcostestimator.com/methodology",
  "note": "present/total is a measurement of the current release, not a promise about the schema. A field may be documented nullable and still be filled on every record of one release.",
  "files": [
    {
      "url": "https://floorcostestimator.com/data/price-band-v1.json",
      "format": "application/json",
      "label": "Full release",
      "description": "Everything: coverage, sample, the pooled band, per-product observations, release confidence and the integrity manifest. Every figure on this site comes from here.",
      "count": 839,
      "countUnit": "products",
      "countedAt": "skus"
    },
    {
      "url": "https://floorcostestimator.com/data/price-band-v1.csv",
      "format": "text/csv",
      "label": "Products, flat",
      "description": "One row per product — identity, box size, observation count, observed low and high, the publisher’s own price. The observations themselves are not in this file; use the JSON for those.",
      "count": 839,
      "countUnit": "rows",
      "countedAt": null
    },
    {
      "url": "https://floorcostestimator.com/data/history.json",
      "format": "application/json",
      "label": "Band by observation date",
      "description": "The pooled band on every archived observation date, each row carrying the number of products and retailers it was measured over, plus a block counting how often an individual price changed from one day to the next.",
      "count": 1,
      "countUnit": "observation date",
      "countedAt": "rows"
    },
    {
      "url": "https://floorcostestimator.com/data/cost-by-size.json",
      "format": "application/json",
      "label": "Cost by job size",
      "description": "The band worked through job sizes: waste allowance, whole-box rounding, billed area and material cost at the lowest, median and highest observation.",
      "count": 12,
      "countUnit": "job sizes",
      "countedAt": "rows"
    },
    {
      "url": "https://floorcostestimator.com/data/dictionary.json",
      "format": "application/json",
      "label": "Field dictionary",
      "description": "The field dictionary as data: every field in the release with its type, unit, whether it may be null, and how many records in the current release actually carry it.",
      "count": 49,
      "countUnit": "documented fields",
      "countedAt": "fields"
    }
  ],
  "fields": [
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "schemaVersion",
      "type": "version",
      "jsType": "string",
      "unit": null,
      "nullable": false,
      "description": "Shape of this file. A change that moves or removes a field raises it; adding a field does not.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "datasetId",
      "type": "identifier",
      "jsType": "string",
      "unit": null,
      "nullable": false,
      "description": "Stable name for the dataset, so successive releases can be recognised as the same series.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "dataAsOf",
      "type": "date",
      "jsType": "string",
      "unit": "ISO 8601 date",
      "nullable": false,
      "description": "The day every price in the file was observed. Not the day the file was written.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "coverage",
      "type": "block",
      "jsType": "object",
      "unit": null,
      "nullable": false,
      "description": "What is priced and what is excluded, in the publisher’s own words: category, manufacturer, geography, price basis, exclusions.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "publisher",
      "type": "block",
      "jsType": "object",
      "unit": null,
      "nullable": false,
      "description": "Who publishes the file and how its own prices compare with the cheapest observation of the same product.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "sample",
      "type": "block",
      "jsType": "object",
      "unit": null,
      "nullable": false,
      "description": "Counts behind the release: products, observations, retailers tracked, retailers that contributed, exact and likely matches, archive depth.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "bands",
      "type": "array of blocks",
      "jsType": "array",
      "unit": null,
      "nullable": false,
      "description": "The pooled price distribution. One entry in this release, segment \"all\": low, p25, median, p75, high.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "confidence",
      "type": "block",
      "jsType": "object",
      "unit": null,
      "nullable": false,
      "description": "Release-level confidence, the fixed rule that decided it, and the reason codes behind it. Not the same scale as a product’s own tier.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "freshness",
      "type": "block",
      "jsType": "object",
      "unit": null,
      "nullable": false,
      "description": "Age of the observation in days and the status derived from it: fresh, aging or stale.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "skus",
      "type": "array of products",
      "jsType": "array",
      "unit": null,
      "nullable": false,
      "description": "One entry per priced product, each carrying the product-level fields documented separately.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "release",
      "field": "manifest",
      "type": "block",
      "jsType": "object",
      "unit": null,
      "nullable": false,
      "description": "Integrity record: source snapshot filename, its SHA-256, its byte and product counts, the generator, and when it ran.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "id",
      "type": "identifier",
      "jsType": "string",
      "unit": null,
      "nullable": false,
      "description": "Slug for the product inside this dataset. Stable between releases; it is not a retailer’s identifier.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "title",
      "type": "text",
      "jsType": "string",
      "unit": null,
      "nullable": false,
      "description": "Product title as a seller states it, including the specification boilerplate. Where two sellers title one product differently, the longer title is kept.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "brand",
      "type": "text",
      "jsType": "string",
      "unit": null,
      "nullable": false,
      "description": "Brand field as the sellers state it, not normalised. Where two sellers spell one maker differently the majority spelling wins the row, and the disagreement is not rewritten away.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "family",
      "type": "text",
      "jsType": "string",
      "unit": null,
      "nullable": true,
      "description": "Construction and installation method, read from the sellers’ own product type and title: glue-down-vinyl, loose-lay-vinyl, floating-vinyl, laminate or engineered-wood. Null where the two sellers describe it differently or neither says — treat null as unknown, never as a default family.",
      "present": 822,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "mfrSku",
      "type": "identifier",
      "jsType": "string",
      "unit": null,
      "nullable": false,
      "description": "Manufacturer SKU. This is the key an exact match is confirmed against.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "boxSqft",
      "type": "number",
      "jsType": "number",
      "unit": "sq ft",
      "nullable": true,
      "description": "Square feet in one sealed box. What billed area rounds up to, and the reason a small job costs more per square foot than a large one.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "z4Psf",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "The publisher’s own advertised price. Named here because the publisher is the one seller this dataset identifies.",
      "present": 46,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "n",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Observations behind this product. 0 means unpriced: report it as unpriced rather than substituting the site-wide band.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "low",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "Cheapest observation of this product. Null when n is 0.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "high",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "Dearest observation of this product. Equal to low when n is 1 — one price, not a range.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "product",
      "field": "obs",
      "type": "array of observations",
      "jsType": "array",
      "unit": null,
      "nullable": false,
      "description": "The observations themselves, in no meaningful order. Empty when n is 0.",
      "present": 839,
      "total": 839
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "observation",
      "field": "psf",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": false,
      "description": "Advertised price normalised to one square foot, materials only, before tax, shipping and any negotiated discount.",
      "present": 1704,
      "total": 1704
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "observation",
      "field": "match",
      "type": "enum",
      "jsType": "string",
      "unit": "strong | weak",
      "nullable": false,
      "description": "strong: the manufacturer SKU was confirmed on the listing. weak: the title matched but the SKU could not be confirmed, so it may be a different specification at the same name.",
      "present": 1704,
      "total": 1704
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "observation",
      "field": "minOrderSqft",
      "type": "number",
      "jsType": "number",
      "unit": "sq ft",
      "nullable": true,
      "description": "Minimum order the listing stated. Null means the listing stated none — not that none exists.",
      "present": 0,
      "total": 1704
    },
    {
      "file": "https://floorcostestimator.com/data/price-band-v1.json",
      "level": "observation",
      "field": "boxSqftDerived",
      "type": "flag",
      "jsType": "boolean",
      "unit": null,
      "nullable": false,
      "description": "True when the listing did not publish a box size and the manufacturer’s figure was used to derive the per-square-foot price.",
      "present": 1704,
      "total": 1704
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "date",
      "type": "date",
      "jsType": "string",
      "unit": "ISO 8601 date",
      "nullable": false,
      "description": "The day the prices behind this row were observed.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "products",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Products the crawl matched that day. It grew during the archive, so two rows are not automatically comparable.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "observations",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Prices pooled into this row’s band.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "sources",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Retailers that contributed at least one price that day. The single largest move in this series is a change in this number, not a change in any price.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "low",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "Cheapest observation pooled across all products that day.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "p25",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "Quarter of the day’s observations sat at or below this.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "median",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "Middle observation of the day. The figure quoted on the rest of the site is this one, for the most recent date.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "p75",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "Three quarters of the day’s observations sat at or below this.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "series",
      "field": "high",
      "type": "price",
      "jsType": "number",
      "unit": "USD/sqft",
      "nullable": true,
      "description": "Dearest observation pooled across all products that day.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "dates",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Observation dates in the archive these figures were computed over.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "comparisons",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Times a price was compared with itself — the same product at the same retailer, one day apart. This is the denominator; the number of observations is not.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "held",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Comparisons where the price was identical to the day before.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "changed",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Comparisons where it was not.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "changedPct",
      "type": "percentage",
      "jsType": "number",
      "unit": "%",
      "nullable": true,
      "description": "changed as a share of comparisons. Null when there is only one date, which is a different statement from a rate of zero.",
      "present": 0,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "moveMinPct",
      "type": "percentage",
      "jsType": "number",
      "unit": "%",
      "nullable": true,
      "description": "Smallest movement among the changes, in percent. Null when nothing changed.",
      "present": 0,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "moveMedianPct",
      "type": "percentage",
      "jsType": "number",
      "unit": "%",
      "nullable": true,
      "description": "Middle movement among the changes. Says how big a change is when one happens, which the rate alone does not.",
      "present": 0,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "moveMaxPct",
      "type": "percentage",
      "jsType": "number",
      "unit": "%",
      "nullable": true,
      "description": "Largest single movement observed in the archive.",
      "present": 0,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "appeared",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Prices seen for the first time on a day. Catalogue churn, counted apart from movement so it cannot inflate the change rate.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "vanished",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Prices that stopped being listed. Also not a movement.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "spanFirst",
      "type": "date",
      "jsType": "string",
      "unit": "ISO 8601 date",
      "nullable": true,
      "description": "First date in the archive.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "spanLast",
      "type": "date",
      "jsType": "string",
      "unit": "ISO 8601 date",
      "nullable": true,
      "description": "Last date in the archive.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "spanPairs",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "Product-and-retailer pairs present on both the first and the last date — the ones that can be compared end to end.",
      "present": 1,
      "total": 1
    },
    {
      "file": "https://floorcostestimator.com/data/history.json",
      "level": "stability",
      "field": "spanIdentical",
      "type": "count",
      "jsType": "number",
      "unit": null,
      "nullable": false,
      "description": "How many of those carried the same price on both. A daily rate cannot answer this: a price that rises and falls back moves twice and ends where it started.",
      "present": 1,
      "total": 1
    }
  ],
  "hazards": [
    {
      "id": "independence",
      "measured": "1704 observations, 156 distinct prices",
      "description": "Counting observations counts catalogue coverage, not independent price checks. A retailer prices a whole product line at one figure and carries it across every colourway, so one decision produces many rows. Any confidence interval computed as though the rows were independent will be far too narrow."
    },
    {
      "id": "min_order",
      "measured": "minOrderSqft is null on 1704 of 1704 observations",
      "description": "Null means the listing did not state a minimum, not that none applies. Treating null as \"no minimum\" reports prices as reachable for small jobs when they may not be."
    },
    {
      "id": "derived_box",
      "measured": "0 of 1704 observations carry a derived box size",
      "description": "The listing did not publish square feet per box, so the manufacturer’s figure was used to compute the price per square foot. Those prices are derived rather than printed, and they are the ones an audit should check first."
    }
  ]
}