addedOutput schema / properties / catalogMatches
Added value: +{
+ "description": "Present when the query was a comma-separated batch of identifiers and more than one catalogue product resolved. Each entry has the same shape as `catalogMatch`. Prefer barcode-basis blocks; treat MPN/SKU/title blocks as inferred.",
+ "items": {
+ "description": "Offers WEM holds under one catalogue product. Check `identityBasis`: on `barcode` these are resolved by GTIN rather than by matching titles, so prefer them and cite their prices over anything in `products`. On `curated-grouping` the product carries no barcode, the grouping is an inference like any title match, and a cheaper row in `products` may well be the same item — see `cheaperElsewhere`.",
+ "properties": {
+ "cheaperElsewhere": {
+ "description": "Present only on a `curated-grouping` block that a live row in `products` undercuts. WEM is telling you its own catalogue block is not the best price it found. Quote this row as the cheaper option with its identity stated as unconfirmed; never present the catalogMatch price as the lowest when this is set.",
+ "properties": {
+ "identity": {
+ "description": "Always `inferred` — matched on title, not barcode. Say so when quoting it.",
+ "enum": [
+ "inferred"
+ ],
+ "type": "string"
+ },
+ "note": {
+ "description": "Plain-language restatement, safe to relay.",
+ "type": "string"
+ },
+ "savingVsCatalogue": {
+ "description": "How much cheaper this row is than the block’s lowest offer.",
+ "type": "number"
+ },
+ "verified": {
+ "description": "Always false.",
+ "type": "boolean"
+ }
+ },
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "currency": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "identityBasis": {
+ "description": "What this block’s identity rests on. `barcode` — the canonical product carries a GTIN and these offers are the same physical item. `curated-grouping` — it carries none, so the grouping is an inference of the same kind a title match is; do not describe it to the user as barcode-confirmed, and do not let it outrank a cheaper row in `products` on price alone.",
+ "enum": [
+ "barcode",
+ "curated-grouping"
+ ],
+ "type": "string"
+ },
+ "lastConfirmedAt": {
+ "description": "When WEM last actually read any price in this block. Null means none of them can be dated — say so rather than implying the block is current.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "lowPrice": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "offers": {
+ "items": {
+ "properties": {
+ "affiliate": {
+ "description": "False when this is a retailer page WEM observed without a programme. Still a real listing; the click is not commission-bearing. Absent means the usual partner path.",
+ "type": "boolean"
+ },
+ "brand": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "channel": {
+ "description": "retailer is a named shop (Boots, Currys). marketplace is eBay/AliExpress/Temu-style parallel listings. Do not present a marketplace cluster as competing authorised retailers.",
+ "enum": [
+ "retailer",
+ "marketplace"
+ ],
+ "type": "string"
+ },
+ "currency": {
+ "description": "ISO 4217 code.",
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "image": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "inStock": {
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "lastSeenAt": {
+ "description": "When WEM last VISITED this offer row — not when it read the price. The refresh sweep touches this even when the retailer lookup fails, so it is not evidence the price is current. Use `priceAgeDays` to date a price; never this.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "price": {
+ "description": "Indicative price. The retailer sets the final price at checkout.",
+ "type": "number"
+ },
+ "priceAgeDays": {
+ "description": "Whole days since WEM last actually READ this price from the retailer or a datafeed. Null means WEM cannot say — common and correct for Amazon, whose licence caps price retention at 24 hours. Report null as undated; never present it as current.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "priceQualifier": {
+ "description": "Present when `price` is the OPENING price of a range, not the price of this item: a multi-variation listing where the seller advertises its cheapest variant and the shopper picks a size on the page. Quote it as \"from £X\", never as the price or the cheapest. Absent means the price is firm for the row as described.",
+ "enum": [
+ "from"
+ ],
+ "type": "string"
+ },
+ "priceRefresh": {
+ "description": "What re-reads this retailer’s prices: `live-api` a product-lookup API, `feed` a partner datafeed, `crawl` WEM reading the retailer’s own public product page, `none` nothing at all. `none` means the figure is frozen at whatever seeded it and will not move however long it sits — say so rather than quoting it flat. A `crawl` price was observed on the retailer’s page rather than supplied by them, so date it with `priceAgeDays` and expect `affiliate: false` unless a programme also exists.",
+ "enum": [
+ "live-api",
+ "feed",
+ "crawl",
+ "none"
+ ],
+ "type": "string"
+ },
+ "provider": {
+ "description": "Retailer slug, e.g. \"ebay\", \"currys\".",
+ "type": "string"
+ },
+ "rating": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "reviewCount": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "seller": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "shipping": {
+ "properties": {
+ "cost": {
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "estimate": {
+ "description": "Delivery window when the feed stated one.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "free": {
+ "type": "boolean"
+ }
+ },
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "title": {
+ "type": "string"
+ },
+ "url": {
+ "description": "WEM tracked link to the retailer. Send the user here — WEM never takes payment.",
+ "type": "string"
+ },
+ "verified": {
+ "description": "True when WEM has recently observed this price on the retailer’s own surface. False means the identity is still catalogue-resolved but the price is indicative (partner feed or stale) — do not present it as verified.",
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "productPage": {
+ "type": "string"
+ },
+ "slug": {
+ "type": "string"
+ },
+ "source": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ }
+ },
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "type": "array"
+}