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

Cheapest nearby

Geo-scoped cheapest-product search. Pass a user's location and a product filter; get back every store within radius that carries the product, sorted by distance ascending then price ascending. The 'where can I buy this for the lowest price near me' workflow.

GET/v1/prices?near={lat,lng}&radius_mi={r}$0.01
⚠
Filter to source_tier='specific' for ranking
For a leaderboard of "cheapest nearby", drop rows where source_tier ≠ "specific" before sorting. Regional/chain fallback rows give you a directional price for a chain that hasn't been re-scraped, but ranking them as if they were verified prices at a specific nearby store will produce phantom-cheapest results.

Required: a product filter + a geo filter

Product side (pick one)

NameTypeDescription
qstringTrigram text search on product name + brand. Used when the user typed a query.
barcodestringUPC or EAN, 6-32 digits. Used when scanning.
product_iduuidSingle canonical product UUID. Used when you've already resolved the catalog entry.
product_idsstringComma-separated UUIDs (cap 50). For comparing multiple variants of a product across nearby stores in one call.

Geo side

NameTypeDescription
nearrequiredstringCaller location as lat,lng, e.g. 40.6892,-73.9942. Both values required.
radius_minumberdefault: 10Search radius in miles. Range 0.1-50. Pulls every source store whose location is within radius.

Workflow: cheapest store within walking distance

Request
curl 'https://api.mainmarket.com/v1/prices?barcode=00016000275287&near=40.6892,-73.9942&radius_mi=2&limit=20' \
  -H "Authorization: Bearer mm_live_..."

Sample response

200 OKjson
{
  "count": 4,
  "results": [
    {
      "product_id": "9d4e1c80-78a3-4a6d-9b1f-2cdb3d0c7e90",
      "name": "Cheerios Cereal, 18 oz",
      "store_id": "ee44...",
      "store_name": "ALDI Brooklyn 4th Ave",
      "chain_slug": "aldi",
      "price": 3.79,
      "regular_price": 3.79,
      "is_on_sale": false,
      "source_tier": "specific",
      "source_distance_mi": 0.0,
      "pricing_scope": "per_store",
      "distance_mi": 0.41
    },
    {
      "product_id": "9d4e1c80-78a3-4a6d-9b1f-2cdb3d0c7e90",
      "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,
      "source_tier": "specific",
      "pricing_scope": "per_store",
      "distance_mi": 0.62
    }
  ]
}

Sort order

With ?near= set, the API sorts results by:

  1. distance_mi ASC — closest source store first
  2. price ASC — within the same distance bucket, cheaper wins

That's the natural "Nearby Prices" ordering for a product-detail screen — closest first, then cheapest. If you want pure cheapest-first regardless of distance, re-sort client-side after filtering to source_tier = "specific".

Two distinct distance fields

NameTypeDescription
distance_minumber | nullUser-to-store distance. Populated only when ?near= was supplied. This is what you display in the UI.
source_distance_minumberSource-store-to-requested-store distance. Always present. 0.0 when source_tier='specific'. Used to caveat fallback rows ('approx — based on a sibling 8mi away').

Combining with a chain filter

Add ?chain=... to scope to one banner. Useful for loyalty-app flows ("show me Wegmans prices nearby for this product") or to compute a chain-specific cheapest-nearby.

curlbash
curl 'https://api.mainmarket.com/v1/prices?barcode=00016000275287&chain=heb&near=29.7604,-95.3698&radius_mi=10' \
  -H "Authorization: Bearer mm_live_..."

Notable behavior

  • Geo + chain combine via AND. All filters narrow the result set. If you pass chain=heb&near=40.6,-73.9 in NYC, you'll get an empty result — there are no H-E-B stores there.
  • radius_mi caps at 50. Pass anything larger and you'll get a 422. Most cheapest-near-me UIs use 2-5 mi; institutional queries use 25-50.
  • Caching. Responses send Cache-Control: public, max-age=30, stale-while-revalidate=120. Prices change roughly hourly; the short TTL keeps typeahead snappy without showing stale rungs.

Errors

NameTypeDescription
422Unprocessable EntityMissing product or geo filter, malformed near=, lat/lng out of range, or radius_mi out of 0.1-50.
402Payment RequiredPaid route — no payment proof.

Related

  • Search prices — full endpoint reference.
  • Prices by UPC — same UPC across every store nationwide (no geo filter).
  • Prices at a store — known store, lookup by id.
  • List stores — pre-flight a geo search (free) before pulling prices.