MainMarketAPI Reference
Get Access
Overview
  • Introduction
  • Authentication
  • Errors
Stores
  • List stores
  • Get a store
  • Store sentiment
  • Store coupons
  • Store aisles
Chains
  • List chains
  • Get a chain
  • Chain aisles
  • Resolve a list
Products
  • Catalog search
  • Get a product
  • Coupons for product
Prices
  • Search prices
  • Prices by UPC
  • Prices at a store
  • Cheapest nearby
Coupons
  • List coupons
  • Get a coupon
  • Coupon savings
Indices
  • Published indices
Discovery & meta
  • Discovery routes
  • OpenAPI spec
  • Agent skill spec
Overview
  • Introduction
  • Authentication
  • Errors
Stores
  • List stores
  • Get a store
  • Store sentiment
  • Store coupons
  • Store aisles
Chains
  • List chains
  • Get a chain
  • Chain aisles
  • Resolve a list
Products
  • Catalog search
  • Get a product
  • Coupons for product
Prices
  • Search prices
  • Prices by UPC
  • Prices at a store
  • Cheapest nearby
Coupons
  • List coupons
  • Get a coupon
  • Coupon savings
Indices
  • Published indices
Discovery & meta
  • Discovery routes
  • OpenAPI spec
  • Agent skill spec

Prices by UPC

Pull every store's current price for a single product (identified by UPC, EAN, or canonical product_id). The classic 'price intelligence' query — useful for tracking a SKU nationally, computing chain-level averages, or finding the cheapest banner that carries a product.

GET/v1/prices?barcode={upc}$0.01
ℹ
Same endpoint as Search prices, different intent
This is /v1/prices with a product filter and no store filter — the response fans out across every store the API has a recent price for. See Search prices for the full parameter reference; this page focuses on the UPC-fanout workflow.

The three ways to identify a product

NameTypeDescription
barcodestringUPC or EAN, 6-32 digits. Matches both raw upc and zero-padded upc_normalized — pass either format. Most common path when you have a scanned barcode.
product_iduuidMainMarket canonical product UUID. Stable forever; UPCs can be reassigned.
product_idsstringComma-separated UUIDs for multi-SKU comparison (e.g. all variants of a brand). Cap 50.

Optional filters to narrow the fanout

NameTypeDescription
chainstringLimit to one chain slug (e.g. wegmans, heb, kroger). Returns one row per store within that chain.
statestringTwo-letter state code. Useful for regional comparisons.
metrostringMetro key (e.g. nyc, sf, dallas).
nearstringGeo filter as lat,lng. Pair with radius_mi for "all stores within X miles that carry this product."
on_salebooleanWhen true, returns only rows where is_on_sale = true. Quick way to find every banner currently running a promo on a SKU.
limitintegerdefault: 50Max rows (1-500). Bump for nationwide queries.

Workflow: chain-by-chain price comparison

Resolve the UPC once, then pull a representative price per chain. Useful for building a "cheapest banner for this product" widget.

Request
# Fan out to all stores nationwide that carry this UPC
curl 'https://api.mainmarket.com/v1/prices?barcode=00016000275287&limit=500' \
  -H "Authorization: Bearer mm_live_..."

Workflow: nationwide on-sale watch

Find every banner currently running a promo on a UPC. Pair with a daily cron to catch new sales as they go live.

Request
curl 'https://api.mainmarket.com/v1/prices?barcode=00016000275287&on_sale=true&limit=500' \
  -H "Authorization: Bearer mm_live_..."

Sample response

200 OK (abbreviated)json
{
  "count": 47,
  "results": [
    {
      "product_id": "9d4e1c80-78a3-4a6d-9b1f-2cdb3d0c7e90",
      "upc": "00016000275287",
      "name": "Cheerios Cereal, 18 oz",
      "store_id": "8c1a4d1e-30a7-4d92-9e1c-1cb43c6f2e10",
      "store_name": "Wegmans Brooklyn",
      "chain_slug": "wegmans",
      "price": 4.99,
      "regular_price": 5.49,
      "sale_price": 4.99,
      "is_on_sale": true,
      "unit_price": 0.28,
      "unit_price_uom": "oz",
      "source_tier": "specific",
      "source_distance_mi": 0.0,
      "pricing_scope": "per_store"
    },
    {
      "product_id": "9d4e1c80-78a3-4a6d-9b1f-2cdb3d0c7e90",
      "upc": "00016000275287",
      "name": "Cheerios Cereal, 18 oz",
      "store_id": "ee44...",
      "store_name": "HEB Houston Heights",
      "chain_slug": "heb",
      "price": 4.49,
      "regular_price": 4.49,
      "sale_price": null,
      "is_on_sale": false,
      "source_tier": "specific",
      "pricing_scope": "per_store"
    }
  ]
}

Notable behavior

  • One row per (store, product) pair. If the UPC matches multiple canonical products (rare but possible — e.g. a product that was reformulated and reused its UPC), you'll get rows for each canonical id. De-dupe on product_id if your UI only wants one.
  • Filter to source_tier = "specific". When you don't pass a store filter, every row should be tier=specific (the API doesn't fall back across stores when no store was asked for). But sanity-check anyway — mixed-tier rows in a national rollup will skew the median.
  • Coverage varies. A UPC may be carried by 700 stores in our catalog and only 400 of them have a recent scrape. Empty price fields should be filtered before computing aggregates.
  • Chain-level pricing collapses. For chains tagged pricing_scope = "chain_level" (Lidl, Trader Joe's, Aldi), every store row carries the same price — collapse to one row per chain to avoid weighting them by store count.

Errors

NameTypeDescription
422Unprocessable EntityNo product filter (you must pass barcode, product_id, or product_ids).
402Payment RequiredPaid route — no payment proof.

Related

  • Search prices — full endpoint reference including every parameter and response field.
  • Prices at a store — flip the query: every product at one store instead of every store for one product.
  • Cheapest nearby — geo-scoped cheapest-by-product query.