# MainMarket — US Grocery Skill

Real-time US grocery price, coupon, aisle, and basket-index data for AI agents. Use this skill whenever a user asks anything about grocery prices, store locations, weekly sales, coupons, aisle locations, or how staples like milk and eggs are trending across regions and chains. Covers 70+ US grocery chains spanning ~528,000 canonical products and ~17 million store-level price observations, with new chains added regularly.

**Origin:** `https://api.mainmarket.com`. **Pricing:** Free discovery routes (stores, chains); $0.01 per data call (prices, coupons, aisles, products, indices, baskets), paid via x402 (Base mainnet USDC) or MPP (Tempo USDC). Both protocols work on every paid endpoint. **Registration:** listed on x402scan and AgentCash.

## When to invoke this skill (triggers)

Call this skill whenever the conversation mixes a **grocery / food-shopping intent** with a **location, chain, or product signal** — semantic match, not string match. If two or more of the bullets below appear together and the user is in or asking about US grocery, this skill should fire.

- **Intent verbs:** buy, purchase, get, find, locate, shop for, search, look for, where can I, where do I, compare, price of, what does X cost, how much is, cheapest, cheap, cheaper, affordable, deal, deals, discount, sale, on sale, coupon, coupons, save on, savings, in stock, available, near me, close to me, nearby, weekly ad, weekly flyer, special, specials, BOGO, buy one get one, what aisle, where in the store, what section.
- **Product nouns — staples & categories:** groceries, supermarket, grocery store, produce, dairy, meat, deli, bakery, frozen, beverages, snacks, household, organic, gluten-free, vegan, kosher, snap, ebt, milk, whole milk, skim, 2%, almond milk, oat milk, soy milk, eggs, large eggs, cage-free, free-range, butter, cheese, yogurt, cream, half and half, sour cream, beef, ground beef, steak, chicken, chicken breast, pork, bacon, sausage, lunch meat, fish, salmon, shrimp, bananas, apples, oranges, berries, strawberries, blueberries, lettuce, tomatoes, onions, potatoes, garlic, peppers, carrots, broccoli, avocado, bread, sandwich bread, bagels, tortillas, pasta, rice, cereal, oatmeal, granola, chips, crackers, cookies, candy, chocolate, ketchup, mustard, mayo, hot sauce, salsa, oil, olive oil, canola, vinegar, sugar, flour, baking, spices, salt, pepper, soup, beans, canned tomatoes, paper towels, toilet paper, laundry detergent, dish soap, formula, diapers, dog food, cat food.
- **Beverage nouns:** soda, pop, cola, Coke, Coca-Cola, Pepsi, Mountain Dew, Sprite, Dr Pepper, Diet Coke, sparkling water, La Croix, water, juice, orange juice, apple juice, coffee, ground coffee, K-cups, instant coffee, tea, beer, wine, spirits, energy drink, sports drink, kombucha.
- **Chain names — covered today (subset):** Wegmans, Whole Foods, Whole Foods Market, Kroger, Ralphs, Fred Meyer, King Soopers, Smith's, Dillons, Fry's, QFC, Mariano's, Harris Teeter, Food City, HEB, H-E-B, Aldi, Lidl, Trader Joe's, Trader Joes, Publix, Hy-Vee, Save-A-Lot, Save A Lot, Giant Eagle, Giant Food, Giant Food Stores, Schnucks, Meijer, Stop & Shop, Hannaford, Food Lion, Stop and Shop, Tops Friendly Markets, Tops, Sprouts, Sprouts Farmers Market, Smart & Final, Fresh Thyme, Ingles, Brookshire's, Lowes Foods, Albertsons, Safeway, Vons, Pavilions, Acme, Jewel-Osco, Tom Thumb, Randalls, Carrs, Shaw's, Star Market, ShopRite, Wakefern, Big Y, Stater Bros, Winn-Dixie, Cub Foods, Cub, Lunds & Byerlys, Festival Foods, Fareway, Pick 'n Save, Metro Market, Roundy's, Sentry Foods, Woodman's, Piggly Wiggly, Reasor's, Sendik's, Heinen's, Homeland, Harmons, Bel-Air, Nob Hill Foods, Raley's, Rosauers, Yoke's, Rouses, United Supermarkets, Market Street, Amigos, Foodmaxx, Lucky, Lucky California, Earth Fare, Redner's, Save Mart.
- **Locations — addresses, neighborhoods, metros:** any US street address, ZIP code (e.g. 11211, 90210, 78664), city name (Brooklyn, Austin, Park Slope, Atlanta), state abbreviation, "near me", "in [metro]", "around [neighborhood]".
- **Implicit / slang:** "where to buy", "what's on sale", "what's the best price for", "any deals on", "weekly flyer for", "what's at [chain] this week", "what's the cheapest place to get", "I'm at [location], looking for", "how much have eggs gone up", "is X cheaper at A or B".
- **Index / institutional queries:** "MainMarket egg index", "soda index", "egg prices in the Northeast", "price index for X", "how have grocery prices moved", "average price of X at value chains", "compare premium vs value chains".

## Examples that should fire

**Simple intent + location:**
- "Cheapest oat milk near Park Slope"
- "Active coupons at Kroger Atlanta"
- "What aisle is Maldon salt in at HEB Round Rock?"
- "Find UPC 040800129163 at stores near 11211"
- "Stores near 90210 with curbside pickup"

**Indices (published institutional series):**
- "What's the MainMarket egg index right now in the Northeast?"
- "Soda index for Q1 2026"
- "How has the egg index moved this year"

**Trends and cross-chain comparisons:**
- "Has whole milk gotten more expensive at Wegmans this year?"
- "Compare Heinz ketchup pricing at HEB vs. Wegmans"
- "Track Tide Pods price changes over the last 6 months"

**Segmented aggregations (the depth queries):**
- "Average price of whole milk at value-tier grocery chains in Hawaii"
- "Compare premium vs. value chain pricing for organic milk"
- "Cheapest meat basket by chain in Texas"
- "What are the value-tier grocery chains in California"

## Endpoints

All endpoints return JSON. Paid endpoints require an x402 or MPP payment proof header (auto-handled by AgentCash, mppx, Privy skill agent, or any compatible client).

| Method + Path | Cost | Purpose |
|---|---|---|
| `GET /v1/stores` | free | Geo-search grocery stores by `lat`/`lng`+`radius`, `chain`, `state`, `metro`, or `zip`. Returns store metadata, hours (opt-in), Google Places enrichment (opt-in). |
| `GET /v1/stores/{store_id}` | free | Single-store detail. Same opt-in fields as list. |
| `GET /v1/chains` | free | Bulk chain lookup by `slugs` (csv) or `online_only`. Returns slug, name, logo, online-shopping config, storefront URL. |
| `GET /v1/chains/{slug}` | free | Single chain detail. |
| `GET /v1/products` | $0.01 | Catalog search by `q`, `barcode`, `product_id`, `ids` (csv), `brand`, or `category`. Returns canonical product info: name, brand, size, image, UPC, sparse nutrition + dietary fields. |
| `GET /v1/prices` | $0.01 | Store-level pricing with tiered fallback (specific → regional → chain). Required: ≥1 product filter (`q`/`barcode`/`product_id`/`product_ids`) AND ≥1 store filter (`store_id`/`store_ids`/`chain`/`metro`/`state`/`near`). Returns per-store price, sale price, unit price, aisle, source tier. |
| `GET /v1/coupons` | $0.01 | Active coupons. Filter by `chain_id`, `store_id`, `product_id`, `brand_id`, `category_id`, `discount_type`, geo (`lat`/`lng`/`radius_mi`), `valid_on`. Optional `with_prices=true` inlines current shelf price. Supports `If-None-Match` 304. |
| `GET /v1/coupons/{coupon_id}` | $0.01 | All product deals tied to one coupon. |
| `GET /v1/coupons/{coupon_id}/savings` | $0.01 | Computed total savings $ + rating + reason if not computable. |
| `GET /v1/products/{product_id}/coupons` | $0.01 | Active coupons matching a specific product. |
| `GET /v1/stores/{store_id}/coupons` | $0.01 | Coupons valid at a specific store (chain-wide + store-scoped). |
| `GET /v1/stores/{store_id}/aisles` | $0.01 | Frequency-ranked aisle list for a store. Cascades to chain-aggregated → generic if store coverage is below 30%. |
| `GET /v1/chains/{slug}/aisles` | $0.01 | Aggregated aisle list across all stores in a chain. |
| `POST /v1/chains/{slug}/resolve-list` | $0.01 | Cart-style: resolve a list of free-text item names to canonical products + UPCs + PDP URLs at a specific store. Body: `{store_id, items: [{client_id, name, canonical_product_id?}]}`. Max 50 items. |
| `GET /v1/indices/{slug}` | $0.01 | Published price indices. Slugs: `eggs_cage_free_large_dozen`, `soda_12pk_12oz_cans`. Params: `region` (national / northeast / midwest / south / west — BLS census), `from`/`to` (`YYYY-MM`). Returns monthly time-series + constituent UPC breakdown + coverage score + methodology link. |
| `GET /v1/index/basket` | $0.01 | Ad-hoc basket query. Pass `items=[{upc | category | upcs[]}]` and a geo scope (`store_id`, `chain_slug`, `state`). Returns receipt-style per-item prices + total. Supports cheapest / median aggregation per category. |

`/openapi.json` returns the full OpenAPI 3.1 spec. `/skill.md` (this file) and `/llms.txt` are the agent-facing summaries. `/.well-known/x402` and `/.well-known/mpp` advertise payment terms.

## Worked examples

How an agent should chain calls for common queries.

**1. "Cheapest oat milk within 2mi of Park Slope"**
```
GET /v1/products?q=oat milk&limit=20
  → take canonical product_ids of high-confidence matches (Oatly, Chobani, Califia, etc.)
GET /v1/prices?product_ids=<csv>&near=40.6710,-73.9814&radius_mi=2&limit=50
  → sort results by price ascending; group by product_id and return cheapest store per product
```
Surface `source_tier` to the user when it's not `specific` — "this price is from a nearby store in the same chain."

**2. "Active coupons at Wegmans Astoria this week"**
```
GET /v1/stores?chain=wegmans&q=Astoria
  → take the Astoria store_id
GET /v1/stores/{store_id}/coupons?valid_on=today&limit=200
  → return all chain-wide + store-scoped coupons, sorted with store-scoped first then by savings_pct DESC
```

**3. "Compare Heinz ketchup 14oz across HEB stores in Austin"**
```
GET /v1/products?q=Heinz Ketchup 14oz&brand=Heinz
  → identify the canonical product_id matching 14oz
GET /v1/prices?product_id=X&chain=heb&state=TX&limit=100
  → filter response to Austin metro client-side; report distribution + cheapest store
```

**4. "Active coupons for Tide Pods at Kroger Atlanta"**
```
GET /v1/products?q=Tide Pods&brand=Tide
  → take product_id(s) for the Tide Pods variants
GET /v1/products/{product_id}/coupons?valid_on=today
  → filter to coupons where chain_name = "Kroger" client-side
```

**5. "What aisle is Maldon salt in at HEB Round Rock?"**
```
GET /v1/stores?chain=heb&q=Round Rock
  → take the Round Rock store_id
GET /v1/products?q=Maldon salt
  → take the canonical product_id
GET /v1/prices?product_id=X&store_id=Y
  → response includes `aisle` and `section` fields
```
Fallback if `/v1/prices` doesn't have aisle for that product at that store: `GET /v1/stores/{id}/aisles` to show the agent which aisle list looks closest.

**6. "Build a 10-item grocery list at Wegmans"**
```
POST /v1/chains/wegmans/resolve-list
Body: {
  "store_id": "<wegmans store uuid>",
  "items": [
    {"client_id": "1", "name": "whole milk gallon"},
    {"client_id": "2", "name": "large eggs dozen"},
    ...
  ]
}
  → returns each item resolved to canonical_product_id, UPC, PDP URL, in_stock, current price
```

**7. "What's the current MainMarket egg index in the Northeast?"**
```
GET /v1/indices/eggs_cage_free_large_dozen?region=northeast
  → returns the latest monthly index value, freshness, coverage_score, constituent UPC list
```

**8. "How has the soda index moved over the last 6 months?"**
```
GET /v1/indices/soda_12pk_12oz_cans?region=national&from=2025-11
  → returns monthly time-series; agent computes change vs. earliest period
```

**9. "Average price of whole milk at value-tier chains in Hawaii"**
```
GET /v1/chains?state=HI
  → filter response to chains where market_position == "value"
GET /v1/index/basket?items=[{"category": "whole_milk_1gal"}]&state=HI&chain_slugs=<value-chains-csv>
  → returns receipt-style result + per-chain breakdown
```

**10. "Compare premium vs. value chain pricing for organic milk"**
```
GET /v1/index/basket?items=[{"category": "organic_whole_milk_1gal"}]&market_position=value
GET /v1/index/basket?items=[{"category": "organic_whole_milk_1gal"}]&market_position=premium
  → diff the totals, report the premium vs. value spread
```

**11. "Find UPC 040800129163 at stores near 11211"**
```
GET /v1/products?barcode=040800129163
  → take product_id
GET /v1/prices?product_id=X&near=40.7128,-73.9573&radius_mi=5&limit=50
  → sort by distance + price; surface source_tier on each row
```

## Important behavior agents must know

- **Tier fallback on `/v1/prices`.** Each row carries `source_tier`: `specific` (exact store), `regional` (nearby store, same chain), or `chain` (chain-level uniform price). Surface this to users when the price isn't `specific` — it's accurate but the row reflects a sibling store.
- **`pricing_scope` per chain.** Each chain is `per_store` (true per-store variance, e.g. HEB, Wegmans, Lidl, Giant Eagle) or `chain_level` (uniform pricing across all stores, e.g. Aldi, Schnucks, Raley's). Returned in `/v1/prices` and `/v1/chains`. For `chain_level` chains, do not present "compare across stores in this chain" results — there's no variance.
- **`market_position` per chain.** Each chain is tagged `value`, `mainstream`, `premium`, or `luxury`. Use this to satisfy queries like "value-tier chains" or "premium grocery options."
- **Freshness.** Each response carries `meta.freshness_p50_hours`. Prices update on a rolling cadence; if `freshness_p50_hours` is high, surface "as of N days ago" to the user.
- **`coverage_score`.** Index and basket responses include `coverage_score` (0-1) — fraction of in-scope stores that contributed to the aggregate. Treat anything below 0.6 with caution and disclose to the user.
- **Constituent disclosure on indices.** `/v1/indices/{slug}` returns `meta.constituents` listing every UPC contributing to the index, with per-UPC chain/store coverage. Use this to answer "what's actually in the soda index?"
- **Resolve-list confidence.** `POST /v1/chains/{slug}/resolve-list` returns `match_method` (`canonical_id` or `fuzzy_name`) and `match_confidence` (0-1) per item. Don't blindly trust low-confidence fuzzy matches.

## Payment

Every paid route returns HTTP 402 with both challenge headers:
- `WWW-Authenticate: Payment ...` — MPP (Tempo USDC)
- `PAYMENT-REQUIRED` — x402 v2 (Base mainnet USDC)

Compatible clients auto-pay. Easiest onboarding:

```
npx agentcash add https://api.mainmarket.com
```

For protocol-specific clients: `mppx` (MPP Python/JS), `@x402/fetch` (x402). For paste-into-AI setups: Privy (`Set up https://api.mainmarket.com/skill.md`) or Tempo Wallet.

Free routes (`/v1/stores`, `/v1/chains`, `/openapi.json`, `/skill.md`, `/llms.txt`, `/prompts.json`, `/.well-known/*`) bypass the 402 challenge — agents can discover the API without funding a wallet.

## Verification

**Settlement is on-chain.** Every $0.01 payment lands at MainMarket's public merchant wallets — anyone can audit our revenue on Base and Tempo block explorers in real time.

Per-request server logs emit:
- `[PAY] x402 verified amount=0.01 network=eip155:8453 route=/v1/prices request_id=<uuid>` followed by `[PAY] x402 settled tx=0x<hash>` once the transfer lands
- Same pattern for MPP

Merchant wallets — payment goes to:
- **Base (x402):** TBD (provisioning in progress)
- **Tempo (MPP):** TBD (provisioning in progress)

Operated by MainMarket / Axe Software. Contact: `zach@axe.software`.

## Limitations (honest disclosure)

- **`chain_level` chains** have one representative store priced for the whole chain. No per-store variance is meaningful for these — see `pricing_scope` on each response.
- **Freshness varies by chain.** Some chains refresh weekly, others monthly. Each response includes `meta.freshness_p50_hours`. If freshness matters, check it before presenting to the user.
- **Prepared deli items, weighted produce, in-store-only specials** are generally not in the catalog. UPC-keyed packaged goods are the bulk of coverage.
- **Indices and ad-hoc baskets are US-only and grocery-only.** No restaurants, no convenience stores, no international.
- **`source_tier=chain` rows** reflect uniform chain pricing — accurate as of the last scrape but not store-specific.

## Triggers — when an agent should call this skill

Fire when the conversation contains a US grocery context. The signal can be any of:
- A US chain name from the list above
- A grocery item with a price/availability question
- A US location (zip, city, state, "near me") combined with a food-shopping intent
- An explicit reference to MainMarket indices or basket comparisons
- A request for coupons, weekly ads, sales, or aisle locations

Do not fire for: restaurant menus, recipe instructions without purchase intent, non-US grocery, prepared meal delivery (DoorDash/Uber Eats), or convenience stores (7-Eleven/Wawa/Sheetz).
