Properties
| Name | Type | Description |
|---|---|---|
| id | string | |
| chainId | stringnull | |
| storeId | stringnull | |
| productId | stringnull | The offer's best link to a curated product (highest-confidence match), or null when the offer is not linked yet. The per-chain linking rate is published on /docs/app-developers; a linked product carri |
| rawName | string | |
| itemKey | stringnull | The offer's stable item identity: a deterministic normalised name+size key, the same across weeks and chains for the same item. It is what /offers/search groups by (k: |
| chainProductRef | stringnull | The chain's own product number, source-qualified (e.g. "rema1000-catalog:61534"), when the offer is linked to the chain's catalog; null otherwise. When set, imageUrl is the chain's own packshot and or |
| price | string | Decimal string (Postgres numeric). |
| originalPrice | stringnull | |
| unitPrice | stringnull | |
| unitPriceUnit | stringnull | Unit of `unitPrice`: per litre, per kilo or per piece. Null when unknown. |
| currency | string | |
| validFrom | string | |
| validTo | string | |
| ingestedAt | string | When this offer was last actually observed by ingest — the freshness signal for "how current is this price". |
| imageUrl | stringnull | |
| volumeMl | integernull | |
| unitCount | integer | |
| priceKind | string | What kind of price this is: 'campaign' — a published offer (leaflet or a chain month-campaign); 'regular' — the everyday shelf price observed in-store. Public API responses today only ever contain 'ca |
| cropUrl | stringnull | Our own verified crop of this offer's leaflet tile — an image of exactly this offer. Present only on chain-scoped lists (chain_slug), null where the chain's crops are not published. |
| matchedProductIds | array | Which of the query's products this offer matched. Present only on product-scoped offer queries (product_id / product_ids / /products/:id/offers). Use this to attribute offers to the products you asked |
| previousPrice | stringnull | SA-0186: what the same item cost in the same chain in its previous catalogue (the newest campaign offer with the same item key whose validity ended within the 21 days before this offer's validFrom). D |
| isNewThisWeek | boolean | SA-0186: true when this campaign offer started within the last 7 days and the chain had no offer for the same item (any price kind) in the 21 days before it. False when unknown. Present on GET /offers |
| dropAmount | string | previousPrice − price, decimal string (DKK), always > 0. |
| dropPercent | number | dropAmount as a percent of previousPrice, one decimal. |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/shelfatlas-com/json-schema/shelfatlas-com-price-drop-schema.json",
"title": "PriceDrop",
"x-generated": "2026-10-31",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/shelfatlas-com-openapi.json#/components/schemas/PriceDrop",
"type": "object",
"additionalProperties": false,
"required": [
"id",
"chainId",
"price",
"validFrom",
"validTo",
"previousPrice",
"isNewThisWeek",
"dropAmount",
"dropPercent"
],
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"chainId": {
"type": [
"string",
"null"
],
"format": "uuid"
},
"storeId": {
"type": [
"string",
"null"
],
"format": "uuid"
},
"productId": {
"type": [
"string",
"null"
],
"format": "uuid",
"description": "The offer's best link to a curated product (highest-confidence match), or null when the offer is not linked yet. The per-chain linking rate is published on /docs/app-developers; a linked product carries ean, brand and package size via GET /products/{id}."
},
"rawName": {
"type": "string"
},
"itemKey": {
"type": [
"string",
"null"
],
"description": "The offer's stable item identity: a deterministic normalised name+size key, the same across weeks and chains for the same item. It is what /offers/search groups by (k:<item_key>) and what /offers/history?item_key= takes. Opaque — compare, never parse."
},
"chainProductRef": {
"type": [
"string",
"null"
],
"description": "The chain's own product number, source-qualified (e.g. \"rema1000-catalog:61534\"), when the offer is linked to the chain's catalog; null otherwise. When set, imageUrl is the chain's own packshot and originalPrice its normal price."
},
"price": {
"type": "string",
"description": "Decimal string (Postgres numeric)."
},
"originalPrice": {
"type": [
"string",
"null"
]
},
"unitPrice": {
"type": [
"string",
"null"
]
},
"unitPriceUnit": {
"type": [
"string",
"null"
],
"enum": [
"l",
"kg",
"stk",
null
],
"description": "Unit of `unitPrice`: per litre, per kilo or per piece. Null when unknown."
},
"currency": {
"type": "string",
"minLength": 3,
"maxLength": 3
},
"validFrom": {
"type": "string",
"format": "date-time"
},
"validTo": {
"type": "string",
"format": "date-time"
},
"ingestedAt": {
"type": "string",
"format": "date-time",
"description": "When this offer was last actually observed by ingest — the freshness signal for \"how current is this price\"."
},
"imageUrl": {
"type": [
"string",
"null"
]
},
"volumeMl": {
"type": [
"integer",
"null"
]
},
"unitCount": {
"type": "integer"
},
"priceKind": {
"type": "string",
"enum": [
"campaign",
"regular"
],
"description": "What kind of price this is: 'campaign' — a published offer (leaflet or a chain month-campaign); 'regular' — the everyday shelf price observed in-store. Public API responses today only ever contain 'campaign' rows — everyday shelf prices are not part of the public catalog API. (Both kinds are real, currently-valid prices where they do appear; this field labels them, it doesn't filter within a response.)"
},
"cropUrl": {
"type": [
"string",
"null"
],
"description": "Our own verified crop of this offer's leaflet tile — an image of exactly this offer. Present only on chain-scoped lists (chain_slug), null where the chain's crops are not published."
},
"matchedProductIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"description": "Which of the query's products this offer matched. Present only on product-scoped offer queries (product_id / product_ids / /products/:id/offers). Use this to attribute offers to the products you asked for; productId is the offer's single best link and may name a product outside the query."
},
"previousPrice": {
"type": [
"string",
"null"
],
"description": "SA-0186: what the same item cost in the same chain in its previous catalogue (the newest campaign offer with the same item key whose validity ended within the 21 days before this offer's validFrom). Decimal string like `price`; null when unknown — no item key, a key without a pack size, a regular shelf price, or no such offer. Present on GET /offers and /offers/price-drops."
},
"isNewThisWeek": {
"type": "boolean",
"description": "SA-0186: true when this campaign offer started within the last 7 days and the chain had no offer for the same item (any price kind) in the 21 days before it. False when unknown. Present on GET /offers and /offers/price-drops."
},
"dropAmount": {
"type": "string",
"description": "previousPrice − price, decimal string (DKK), always > 0."
},
"dropPercent": {
"type": "number",
"description": "dropAmount as a percent of previousPrice, one decimal."
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/shelfatlas-com-price-drop"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.