{"openapi":"3.1.0","info":{"title":"AZ Labs Grocery Data API","version":"1.0.0","summary":"Live grocery prices from five South African retailers, for AI agents and apps.","description":"Compare current catalogue prices at Pick n Pay, Checkers, Shoprite, Woolworths and Makro in one call.\nUse it when a shopper asks where something is cheapest, what is on promotion, or what a basket costs at each store.\n\nGuidance for agents:\n- Prefer /compare for \"where is X cheapest\" questions: it pairs identical products across retailers and names the cheapest store.\n- Prefer POST /optimize-basket for multi-item shopping lists or recipes: it ranks single-store totals and computes the optimal split basket.\n- Use POST /compare-payload when your app or device already fetched store product payloads and needs SKU normalization and GS1 barcode matching.\n- Quote prices in rand (ZAR) and say which store or zone they are for (`pricedAt`).\n- `cheapestStores` only counts offers with confirmed stock; `lowestPriceStores` also counts offers whose stock is unknown. Say so when they differ.\n- Products have a `url` that opens the retailer's own product page. Send the shopper there to buy; this API never takes orders. Some retailers publish no product links, so `url` can be null.\n- Prices are fetched live (`fetchedAt`) and can differ from a branch's shelf.\n\nPublic retail prices are passed through at R0.00. Create a free API key at https://azlabs.ai/dashboard. Compute tiers (https://azlabs.ai/products/grocery-api#pricing): Free: 50 a day, 250 a month; Starter: 1,000 a day, 25,000 a month; Pro: 6,000 a day, 150,000 a month; Enterprise: 50,000 a day, 1,000,000 a month.\nThe Free tier covers pnp, checkers, woolworths; Starter (R399/mo), Pro (R1,499/mo), and Enterprise add every retailer, smart-basket optimization, and (on Pro/Enterprise) GS1 barcode matching.","contact":{"name":"AZ Labs","url":"https://azlabs.ai/contact"},"termsOfService":"https://azlabs.ai/terms"},"externalDocs":{"description":"Documentation and live demo","url":"https://azlabs.ai/products/grocery-api#developers"},"servers":[{"url":"https://azlabs.ai/api/v1/grocery","description":"Production"}],"security":[{"apiKey":[]}],"paths":{"/compare":{"get":{"operationId":"compareGroceryPrices","summary":"Find where a product is cheapest","description":"Searches every retailer the tier covers, pairs identical products by pack size and name (or barcode), and ranks the offers.","parameters":[{"name":"q","in":"query","required":true,"description":"What the shopper wants, in plain words, e.g. \"2L Coke\" or \"Jungle Oats 1kg\". Include the size for tighter matches.","schema":{"type":"string","minLength":1,"maxLength":80},"example":"2L Coke"},{"name":"area","in":"query","required":false,"description":"Province the shopper is in. Each retailer prices for the nearest place it supports and says so in `locations`. Defaults to western-cape.","schema":{"type":"string","enum":["western-cape","gauteng","kwazulu-natal","eastern-cape","free-state","limpopo","mpumalanga","north-west","northern-cape"],"default":"western-cape"}},{"name":"limit","in":"query","required":false,"description":"Products per retailer.","schema":{"type":"integer","minimum":1,"maximum":20,"default":5}},{"name":"include","in":"query","required":false,"description":"Set to \"barcodes\" for EAN/GTIN codes (Pro and Enterprise tiers). Other tiers get the answer without barcodes and a notice.","schema":{"type":"string","enum":["barcodes"]}}],"responses":{"200":{"description":"Matched offers across retailers.","headers":{"X-AZL-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Daily request allowance."},"X-AZL-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left today."},"X-AZL-Monthly-Remaining":{"schema":{"type":"integer"},"description":"Requests left this month."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareResponse"}}}},"400":{"description":"A parameter is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The account does not have Grocery API access, or the tier does not cover the requested retailer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The daily or monthly allowance is used up. Retry after the time in Retry-After.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the allowance resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/search":{"get":{"operationId":"searchGroceryProducts","summary":"Search products at one or all retailers","parameters":[{"name":"q","in":"query","required":true,"description":"What the shopper wants, in plain words, e.g. \"2L Coke\" or \"Jungle Oats 1kg\". Include the size for tighter matches.","schema":{"type":"string","minLength":1,"maxLength":80},"example":"2L Coke"},{"name":"store","in":"query","required":false,"description":"One retailer, or all.","schema":{"type":"string","enum":["pnp","checkers","shoprite","woolworths","makro","all"],"default":"all"}},{"name":"area","in":"query","required":false,"description":"Province the shopper is in. Each retailer prices for the nearest place it supports and says so in `locations`. Defaults to western-cape.","schema":{"type":"string","enum":["western-cape","gauteng","kwazulu-natal","eastern-cape","free-state","limpopo","mpumalanga","north-west","northern-cape"],"default":"western-cape"}},{"name":"limit","in":"query","required":false,"description":"Products per retailer.","schema":{"type":"integer","minimum":1,"maximum":20,"default":5}},{"name":"include","in":"query","required":false,"description":"Set to \"barcodes\" for EAN/GTIN codes (Pro and Enterprise tiers). Other tiers get the answer without barcodes and a notice.","schema":{"type":"string","enum":["barcodes"]}}],"responses":{"200":{"description":"Products per retailer.","headers":{"X-AZL-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Daily request allowance."},"X-AZL-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left today."},"X-AZL-Monthly-Remaining":{"schema":{"type":"integer"},"description":"Requests left this month."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"A parameter is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The account does not have Grocery API access, or the tier does not cover the requested retailer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The daily or monthly allowance is used up. Retry after the time in Retry-After.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the allowance resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products":{"get":{"operationId":"getGroceryProduct","summary":"Look up one product by its retailer id","parameters":[{"name":"store","in":"query","required":true,"schema":{"type":"string","enum":["pnp","checkers","shoprite","woolworths","makro"]}},{"name":"id","in":"query","required":true,"description":"The `productId` from a search or compare result.","schema":{"type":"string"}},{"name":"include","in":"query","required":false,"description":"Set to \"barcodes\" for EAN/GTIN codes (Pro and Enterprise tiers). Other tiers get the answer without barcodes and a notice.","schema":{"type":"string","enum":["barcodes"]}}],"responses":{"200":{"description":"The product.","content":{"application/json":{"schema":{"type":"object","required":["store","product"],"properties":{"store":{"type":"string","enum":["pnp","checkers","shoprite","woolworths","makro"]},"product":{"$ref":"#/components/schemas/Product"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"}}}}}}},"400":{"description":"A parameter is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The account does not have Grocery API access, or the tier does not cover the requested retailer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The retailer does not list that product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The daily or monthly allowance is used up. Retry after the time in Retry-After.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the allowance resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stores":{"get":{"operationId":"listGroceryRetailers","summary":"Retailers, what they report, and which the key's tier covers","description":"Does not use any of the allowance.","responses":{"200":{"description":"Supported retailers.","content":{"application/json":{"schema":{"type":"object","properties":{"country":{"type":"string","const":"ZA"},"plan":{"type":"string"},"count":{"type":"integer"},"retailers":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/optimize-basket":{"post":{"operationId":"optimizeGroceryBasket","summary":"Optimize a multi-item grocery basket or recipe across retailers","description":"Resolves up to 15 items across covered retailers (or from a caller-supplied byStoreByItem payload), normalizes pack sizes and loyalty prices, ranks single-store fulfilment totals, and computes the optimal multi-store split basket.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizeBasketRequest"}}}},"responses":{"200":{"description":"Single-store rankings and optimal split-basket breakdown.","headers":{"X-AZL-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Daily request allowance."},"X-AZL-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left today."},"X-AZL-Monthly-Remaining":{"schema":{"type":"integer"},"description":"Requests left this month."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizeBasketResponse"}}}},"400":{"description":"A parameter is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The account does not have Grocery API access, or the tier does not cover the requested retailer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The daily or monthly allowance is used up. Retry after the time in Retry-After.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the allowance resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/compare-payload":{"post":{"operationId":"compareGroceryPayload","summary":"Normalize and match a caller-supplied multi-store product payload (BYO-Payload)","description":"Zero-scraping compute endpoint. Accepts product arrays keyed by store and applies AZ Labs pack-size normalization, unit-price math, and GS1 barcode / fuzzy entity resolution.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComparePayloadRequest"}}}},"responses":{"200":{"description":"Matched offers across the caller-supplied store catalogues.","headers":{"X-AZL-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Daily request allowance."},"X-AZL-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left today."},"X-AZL-Monthly-Remaining":{"schema":{"type":"integer"},"description":"Requests left this month."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareResponse"}}}},"400":{"description":"A parameter is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The account does not have Grocery API access, or the tier does not cover the requested retailer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The daily or monthly allowance is used up. Retry after the time in Retry-After.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the allowance resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"sk-azl-live-…","description":"Free key from https://azlabs.ai/dashboard. Send as Authorization: Bearer <key>."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"Notice":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","examples":["stores_require_plan","barcodes_require_plan","no_results"]},"message":{"type":"string"},"requiredPlan":{"type":"string"}}},"Location":{"type":"object","properties":{"label":{"type":"string","description":"The store, zone or delivery area the price is for."},"exact":{"type":"boolean","description":"False when the retailer falls back to a reference store for this area."},"pricing":{"type":"string"},"stock":{"type":"string"}}},"Product":{"type":"object","required":["store","storeName","productId","name","price","inStock","promotions"],"properties":{"store":{"type":"string","enum":["pnp","checkers","shoprite","woolworths","makro"]},"storeName":{"type":"string"},"productId":{"type":"string"},"name":{"type":"string","description":"Includes the pack size."},"price":{"type":["number","null"],"description":"Shelf price in ZAR."},"priceFormatted":{"type":"string","examples":["R29.99"]},"memberPrice":{"type":["number","null"],"description":"Lower loyalty-card price when the retailer publishes one."},"oldPrice":{"type":["number","null"],"description":"Price before the promotion."},"inStock":{"type":"boolean","description":"True only when stock is confirmed."},"stockState":{"type":"string","enum":["in_stock","out_of_stock","unknown"]},"promotions":{"type":"array","items":{"type":"string"},"examples":[["Buy 2 For R42"]]},"imageUrl":{"type":["string","null"]},"url":{"type":["string","null"],"description":"Buy link: opens the retailer's own product page through a short AZ Labs referral redirect. Use this when sending a shopper to buy."},"retailerUrl":{"type":"string","description":"The same retailer page as a direct link, tagged utm_source=azlabs."},"fetchedAt":{"type":"string","format":"date-time"},"barcodes":{"type":"array","items":{"type":"string"}}}},"Offer":{"$ref":"#/components/schemas/Product"},"Match":{"type":"object","required":["name","offers","cheapestStores","lowestPriceStores"],"properties":{"name":{"type":"string"},"size":{"type":["string","null"],"examples":["2l","6x500ml"]},"offers":{"type":"array","items":{"$ref":"#/components/schemas/Offer"}},"cheapestStores":{"type":"array","items":{"type":"string"},"description":"Lowest price among offers with confirmed stock."},"lowestPriceStores":{"type":"array","items":{"type":"string"},"description":"Lowest price among offers not known to be out of stock."},"saving":{"type":["number","null"],"description":"ZAR saved against the dearest confirmed in-stock offer."},"matchedBy":{"type":"string","enum":["barcode","name"]}}},"CompareResponse":{"type":"object","required":["query","matches","unmatched","errors"],"properties":{"query":{"type":"string"},"matches":{"type":"array","items":{"$ref":"#/components/schemas/Match"}},"unmatched":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}},"errors":{"type":"object","additionalProperties":{"type":"string"},"description":"Retailers that failed this time; the rest still answer."},"fetchedAt":{"type":"string","format":"date-time"},"area":{"type":"string","enum":["western-cape","gauteng","kwazulu-natal","eastern-cape","free-state","limpopo","mpumalanga","north-west","northern-cape"]},"pricedAt":{"type":"object","additionalProperties":{"type":"string"}},"locations":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Location"}},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"}}}},"SearchResponse":{"type":"object","required":["query","stores","products","errors"],"properties":{"query":{"type":"string"},"stores":{"type":"array","items":{"type":"string"}},"products":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"errors":{"type":"object","additionalProperties":{"type":"string"}},"fetchedAt":{"type":"string","format":"date-time"},"area":{"type":"string","enum":["western-cape","gauteng","kwazulu-natal","eastern-cape","free-state","limpopo","mpumalanga","north-west","northern-cape"]},"pricedAt":{"type":"object","additionalProperties":{"type":"string"}},"locations":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Location"}},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"}}}},"OptimizeBasketRequest":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":15,"description":"List of item queries (strings or { query, quantity } objects).","items":{"oneOf":[{"type":"string"},{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"quantity":{"type":"integer","minimum":1,"maximum":50,"default":1}}}]}},"area":{"type":"string","enum":["western-cape","gauteng","kwazulu-natal","eastern-cape","free-state","limpopo","mpumalanga","north-west","northern-cape"],"default":"western-cape"},"include":{"type":"string","enum":["barcodes"]},"includeDeliveryFees":{"type":"boolean","default":false},"byStoreByItem":{"type":"object","description":"Optional caller-supplied catalogues keyed by item query and store slug for zero-scraping BYO-payload basket optimization.","additionalProperties":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}}}}},"OptimizeBasketResponse":{"type":"object","required":["mode","items","singleStoreOptions","optimalSplitBasket","errors"],"properties":{"mode":{"type":"string","enum":["live-compute","byo-payload"]},"items":{"type":"array","items":{"type":"object"}},"singleStoreOptions":{"type":"array","items":{"type":"object"}},"optimalSplitBasket":{"type":"object"},"area":{"type":"string","enum":["western-cape","gauteng","kwazulu-natal","eastern-cape","free-state","limpopo","mpumalanga","north-west","northern-cape"]},"pricedAt":{"type":"object","additionalProperties":{"type":"string"}},"locations":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Location"}},"errors":{"type":"object","additionalProperties":{"type":"string"}},"fetchedAt":{"type":"string","format":"date-time"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"}}}},"ComparePayloadRequest":{"type":"object","required":["byStore"],"properties":{"query":{"type":"string","description":"Optional label for the product comparison."},"area":{"type":"string","enum":["western-cape","gauteng","kwazulu-natal","eastern-cape","free-state","limpopo","mpumalanga","north-west","northern-cape"],"default":"western-cape"},"include":{"type":"string","enum":["barcodes"]},"byStore":{"type":"object","description":"Map of retailer slug to product arrays fetched on the caller's device.","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}}}}}}}