---
title: "List offers"
method: GET
path: "/api/v1/public/catalog/offers"
tags: ["Offers"]
---

# List offers

`GET /api/v1/public/catalog/offers`

## Request

- Base URL: `https://api.shelfatlas.com`
- URL: `https://api.shelfatlas.com/api/v1/public/catalog/offers`
- Auth: HTTP bearer

Filter by a single product, a batch of products, a brand, or a chain. product_id / product_ids / brand_slug / chain_slug cannot be combined.

## Query parameters

- `product_id` string, uuid
- `product_ids` string
- `brand_slug` string
- `chain_slug` string
- `ingested_since` string, date-time
- `cursor` string, nullable
- `limit` integer

## Response `200`

A page of offers.

- object
  - `ok` true, required
  - `data` Offer[], required
    - `id` string, uuid, required
    - `chainId` string, uuid, nullable
    - `storeId` string, uuid, nullable
    - `productId` string, uuid, nullable: 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` string
    - `itemKey` string, nullable: 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.
    - `price` string: Decimal string (Postgres numeric).
    - `originalPrice` string, nullable
    - `unitPrice` string, nullable
    - `unitPriceUnit` 'l' | 'kg' | 'stk' | 'null', nullable: Unit of `unitPrice`: per litre, per kilo or per piece. Null when unknown.
    - `currency` string
    - `validFrom` string, date-time
    - `validTo` string, date-time
    - `ingestedAt` string, date-time: When this offer was last actually observed by ingest — the freshness signal for "how current is this price".
    - `imageUrl` string, nullable
    - `volumeMl` integer, nullable
    - `unitCount` integer
    - `priceKind` 'campaign' | 'regular': 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` string, nullable: 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` string[]: 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` string, nullable: 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` 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 and /offers/price-drops.
  - `pagination` object
    - `limit` integer: The effective page size.
    - `cursor` string, nullable: Opaque cursor for the next page; null on the last page.

## Other responses

- `400`: Invalid parameters (`invalid_params`, `incompatible_params`).
- `401`: Missing, invalid, or revoked API key (`missing_api_key` / `invalid_api_key` / `revoked_api_key`).
- `404`: The requested chain_slug does not exist (`chain_not_found`).
- `429`: Rate limit or monthly limit reached (`rate_limited` / `monthly_limit_reached`).
- `503`: Temporary backend failure (`service_unavailable`).

---

[API](https://skmtc.dev/shelfatlas/apis/shelfatlas-catalog-api.md) · [All operations](https://skmtc.dev/shelfatlas/apis/shelfatlas-catalog-api/llms.txt) · [OpenAPI document](https://skmtc.dev/shelfatlas/apis/shelfatlas-catalog-api/revisions/943a8773856b?raw)
