Active grocery coupons across all tracked chains. Filterable by chain, store, product, brand, category, discount type, and geography. ETag-aware for cheap re-polls.
/v1/coupons$0.01| Name | Type | Description |
|---|---|---|
chain_id | uuid | Limit to one chain. |
store_id | uuid | Limit to coupons valid at one store (chain-wide + store-scoped). |
product_id | uuid | Limit to coupons matching one canonical product. |
brand_id | uuid | Limit to one brand. |
category_id | uuid | Limit to one category. |
| Name | Type | Description |
|---|---|---|
discount_type | string | One of percent_off, dollar_off, bogo, bundle, loyalty_price, featured. |
exclude_featured | booleandefault: false | Drop discount_type='featured' rows. |
is_digital_only | boolean | Filter on whether the coupon clips digitally only (vs. cut-out / paper). |
requires_loyalty | boolean | Filter on loyalty-program requirement. |
valid_on | date | ISO date YYYY-MM-DD. Filters to coupons whose valid_from ≤ valid_on ≤ valid_to. Defaults to today. |
is_active | booleandefault: true | When false, includes expired/disabled coupons. |
| Name | Type | Description |
|---|---|---|
lat | number | Latitude, paired with lng + radius_mi. |
lng | number | Longitude. |
radius_mi | numberdefault: 25 | Miles. Range 0.1–50. |
| Name | Type | Description |
|---|---|---|
with_prices | booleandefault: false | When true, joins each coupon to live store_product_prices and adds current_price, regular_price, is_on_sale, and prices_by_store fields. |
price_store_id | uuid | Single store id to source the joined prices from. |
price_store_ids | string | Comma-separated store ids; populates prices_by_store with one entry per store. |
| Name | Type | Description |
|---|---|---|
limit | integerdefault: 50 | Range 1–200 (geo calls allow 200 to fan out farther). |
offset | integerdefault: 0 | Cursor offset. |
ETag hash. Subsequent calls with the same params and If-None-Match: <etag> return 304 Not Modified with no body. Use this to keep a coupon list fresh without paying for unchanged responses.curl 'https://api.mainmarket.com/v1/coupons?chain_id=12d6...&exclude_featured=true&limit=50'{
"count": 1,
"results": [
{
"id": "0bc5b1d4-9a25-4d70-8a82-2ab3f6f1d901",
"chain_id": "12d6...",
"chain_name": "HEB",
"chain_logo_url": "https://.../heb.png",
"store_id": null,
"product_id": "9d4e...",
"product_name": "HEB Whole Milk",
"product_brand": "HEB",
"product_image_url": "https://.../milk.jpg",
"discount_type": "dollar_off",
"discount_value": 1.00,
"min_purchase_qty": 1,
"description": "$1 off any HEB gallon milk",
"fine_print": "Limit 4 per transaction",
"coupon_code": null,
"valid_from": "2026-04-29",
"valid_to": "2026-05-13",
"image_url": "https://.../coupon.png",
"is_digital_only": true,
"requires_loyalty": true,
"is_clippable": true,
"deep_link_url": "heb://coupons/0bc5...",
"source": "heb",
"source_url": "https://www.heb.com/coupons/...",
"size_text": "1 gal",
"value_text": "$1 off",
"catalog_price": 4.49,
"total_savings": 1.00,
"total_savings_basis": "catalog_price",
"savings_pct": 22.27,
"rating": "good",
"deal_price": 3.49,
"bogo_get_qty": null,
"min_purchase_amount": null,
"role": "buy"
}
]
}| Name | Type | Description |
|---|---|---|
id | uuid | Stable coupon id. |
chain_id, chain_name, chain_logo_url | mixed | Owning chain metadata. |
store_id | uuid | null | Store id when the coupon is store-scoped; null for chain-wide coupons. |
product_id, product_name, product_brand, product_image_url | mixed | Linked canonical product, when matched. Null for unmatched / multi-product coupons. |
discount_type | string | One of percent_off, dollar_off, bogo, bundle, loyalty_price, featured. |
discount_value | number | Magnitude. % for percent_off, $ for dollar_off, multiplier for bogo. |
min_purchase_qty | integer | null | Minimum item count to trigger the coupon. |
min_purchase_amount | number | null | Minimum basket subtotal in USD. |
bogo_get_qty | integer | null | Get-leg quantity for BOGO coupons (e.g. buy 2 get 1 free → bogo_get_qty=1). |
description, fine_print | string | null | Customer-facing copy. |
coupon_code | string | null | Code to enter at checkout, when applicable. |
valid_from, valid_to | date | Inclusive validity window. |
image_url | string | null | Coupon artwork. |
is_digital_only, requires_loyalty, is_clippable | boolean | Behavior flags. |
deep_link_url | string | null | Deep link into the chain's app or coupon-clip flow. |
source, source_url | string | null | Where we scraped the coupon from. |
size_text, value_text | string | null | Free-text size and value labels as printed (e.g. '1 gal', '$1 off'). |
catalog_price | number | null | Baseline regular price used for savings_pct. |
total_savings | number | null | Best-case dollar savings. |
total_savings_basis | string | null | What total_savings was derived from: catalog_price, store_price, or null. |
savings_pct | number | null | 0.0–100.0. Null when no baseline available. |
rating | string | null | Internal label: great, good, okay, poor. |
deal_price | number | null | Effective per-unit price after the coupon clips. |
role | string | For BOGO/bundle: buy (qualifies the coupon), get (the freebie), or either. |
{
"count": 1,
"results": [
{
"id": "0bc5...",
"product_name": "HEB Whole Milk",
"discount_type": "dollar_off",
"discount_value": 1.00,
"deal_price": 3.49,
"current_price": 4.49,
"regular_price": 4.49,
"is_on_sale": false,
"price_store_id": "8c1a...",
"prices_by_store": {
"8c1a...": { "price": 4.49, "is_on_sale": false }
}
}
]
}| Name | Type | Description |
|---|---|---|
current_price | number | null | Live effective price at the joined store. |
regular_price | number | null | Live regular price (pre-sale). |
is_on_sale | boolean | True when current_price < regular_price. |
price_store_id | uuid | Store id the price was joined from (single-store mode). |
prices_by_store | object | When price_store_ids is supplied, a map of store_id → { price, is_on_sale } entries. |
catalog_price and savings math. The id field is the coupon UUID, so it is not unique within a response. Clients keying by id should use the (id, product_id) tuple. Coupons with zero matched canonical products are suppressed entirely.store_id set) match when their store is within radius. Chain-wide coupons (store_id null) match when any store in that chain is within radius. Both arms hit the GiST index on stores.location; the response shape is the same either way.valid_to ASC (soonest expiry first), then savings_pct DESC.lat+lng+radius_mi) bump the limit ceiling to 200 to give clients a wider radius without paginating.| Name | Type | Description |
|---|---|---|
422 | Unprocessable Entity | Bad date format, lat/lng out of range, or limit out of range. |
402 | Payment Required | Paid route — no payment proof. |
500 | Internal Server Error | Unexpected server fault. |