# Woolworths API scraper — woolworths.com.au (Australia) supermarket and Everyday Market: search products, read the full product record with shelf price, was-price and special, cup (unit) price, multi-buy offers, per-kg and variable-weight pricing, availability, marketplace seller, ratings and reviews, ingredients, allergens and the nutrition panel; browse categories and the site's specials pages. Prices in AUD. No account, no browser.

> Search woolworths.com.au by keyword. Each product comes with its shelf price, was-price and discount when on special, the cup (unit) price, multi-buy offer, per-kg or variable-weight pricing, availability, star rating, badges, and the marketplace seller for Everyday Market items. Sort by price or name, keep only specials, filter by brand. Paid placements are removed unless you ask for them.
> ReefAPI engine `woolworths` · 7 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/woolworths/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /woolworths/v1/search — 1 credit
Search woolworths.com.au by keyword. Each product comes with its shelf price, was-price and discount when on special, the cup (unit) price, multi-buy offer, per-kg or variable-weight pricing, availability, star rating, badges, and the marketplace seller for Everyday Market items. Sort by price or name, keep only specials, filter by brand. Paid placements are removed unless you ask for them.

**Parameters:**
- `query` (string, required) — What to look for, as a shopper would type it on woolworths.com.au ('milk', 'tim tam', 'dog food').
- `page` (integer, optional, default 1) — Result page, 1-based. Read `count`, `total_results` and `page_count`.
- `page_size` (integer, optional, default 24) — Products per page, 1-36 (Woolworths' own maximum). Sponsored placements are on top of this and removed by default.
- `sort` (enum, optional, default "relevance") — Result order. [one of: relevance, price_asc, price_desc, name_asc, name_desc]
- `specials_only` (boolean, optional, default false) — true = the site's own 'Specials' toggle: products on a price special AND products with a Buy More Save More multi-buy offer (`multi_buy`). Unavailable products can appear with their price hidden.
- `brand` (string, optional) — Only this brand, spelled exactly as in a row's `brand` (case-sensitive: 'Cadbury' works, 'cadbury' returns nothing).
- `include_sponsored` (boolean, optional, default false) — false (default) drops paid 'Promoted' placements, which Woolworths puts at fixed positions regardless of your sort; true keeps them, flagged `sponsored: true`.
- `include_ratings` (boolean, optional, default true) — true (default) adds each row's star rating and rating count (one extra lightweight lookup for the whole page).
- `max_rotations` (integer, optional, default 3) — Advanced: how many times to retry a difficult request (1-6, default 3).

**Returns:** results[]{product_id (stockcode, string), title, name, brand, package_size, barcode (EAN/GTIN), url, image, breadcrumb[]{level,id,name}, price (number, AUD — the shelf price; per kg when price_per='kg'; null when the product is unavailable), price_display, currency=AUD, original_price (the was-price, only when on special), original_price_display, savings, discount_percent, on_special, half_price, member_price (null — Woolworths published no member price to an anonymous visitor), member_unit_price_text, unit_price, unit_price_measure ('1L', '100G', '1KG', '1EA'), unit_price_text ('$1.65 / 1L'), sold_by ('piece' | 'weight'), price_per ('each' | 'kg'), increment_price, increment_grams, price_min, price_max, price_is_estimate (variable-weight packs), approx_weight_grams, multi_buy{quantity,total_price,price_each,unit_price_text,text} (never subtracted from price), availability ('in_stock' | 'unavailable' | 'not_ranged'), available, in_stock, next_available_date, max_order_quantity (an order limit, not stock), badges[]{type ('label'|'roundel'|'offer'),text,promotion}, promotion_types[], rewards_points_offer, new, online_only, marketplace, seller{type ('retailer'|'marketplace'),name,id,delivery_fee,free_shipping,dispatch_note,delivery_from,delivery_to}, has_variants, sponsored, fulfilment_store_id, rating (0-5), rating_count, review_count, rating_scale (5), rating_distribution{5,4,3,2,1}}, count, total_results, page, page_size, page_count, sponsored_dropped, filters_available{departments[]{id,name,count}, brands[]{name,value,count}}, suggested_query, corrections[], related_terms[], query

**Example request body:**
```json
{
  "query": "milk"
}
```

### POST /woolworths/v1/product/detail — 1 credit
The full Woolworths product record by stockcode (or product URL): title, brand, barcode, every image, shelf price, was-price and savings, cup price, multi-buy offer, per-kg or variable-weight pricing, availability, star rating with distribution, ingredients, allergens (contains / may contain / free from), dietary claims, Health Star Rating, the nutrition panel, the country-of-origin label, storage and warnings, product specs, variants (Everyday Market) and the seller.

**Parameters:**
- `product_id` (string, required) — Woolworths stockcode (the number every row returns as `product_id`) or a woolworths.com.au product URL.
- `max_rotations` (integer, optional, default 3) — Advanced: how many times to retry a difficult request (1-6, default 3).

**Returns:** product{product_id (stockcode, string), title, name, brand, package_size, barcode (EAN/GTIN), url, image, breadcrumb[]{level,id,name}, price (number, AUD — the shelf price; per kg when price_per='kg'; null when the product is unavailable), price_display, currency=AUD, original_price (the was-price, only when on special), original_price_display, savings, discount_percent, on_special, half_price, member_price (null — Woolworths published no member price to an anonymous visitor), member_unit_price_text, unit_price, unit_price_measure ('1L', '100G', '1KG', '1EA'), unit_price_text ('$1.65 / 1L'), sold_by ('piece' | 'weight'), price_per ('each' | 'kg'), increment_price, increment_grams, price_min, price_max, price_is_estimate (variable-weight packs), approx_weight_grams, multi_buy{quantity,total_price,price_each,unit_price_text,text} (never subtracted from price), availability ('in_stock' | 'unavailable' | 'not_ranged'), available, in_stock, next_available_date, max_order_quantity (an order limit, not stock), badges[]{type ('label'|'roundel'|'offer'),text,promotion}, promotion_types[], rewards_points_offer, new, online_only, marketplace, seller{type ('retailer'|'marketplace'),name,id,delivery_fee,free_shipping,dispatch_note,delivery_from,delivery_to}, has_variants, sponsored, fulfilment_store_id, rating (0-5), rating_count, review_count, rating_scale (5), rating_distribution{5,4,3,2,1}, images[], primary_aisle{department,aisle}, description, ingredients, allergens{contains[],may_contain[],free_from[]}, dietary[], health_star_rating, storage_instructions, directions, warnings, country_of_origin{label,country,australian_ingredients_percent}, nutrition{serving_size,servings_per_pack,rows[]{name,per_serving,per_100}}, specs{label: value}, variants[]{product_id,title,options,price,original_price,in_stock,available,primary,image}, variant_options[]{name,values[]}, variant_title, bundle_groups[]}

**Example request body:**
```json
{
  "product_id": "888140"
}
```

### POST /woolworths/v1/product/reviews — 1 credit
Customer reviews shown on a Woolworths product page, paged, newest first: star rating, text, reviewer nickname, date, and the source (including reviews syndicated from partner retailers), plus the product's rating summary.

**Parameters:**
- `product_id` (string, required) — Woolworths stockcode (the number every row returns as `product_id`) or a woolworths.com.au product URL.
- `page` (integer, optional, default 1) — Result page, 1-based. Read `count`, `total_results` and `page_count`.
- `page_size` (integer, optional, default 10) — Reviews per page, 1-50.
- `sort` (enum, optional, default "latest") — Review order. [one of: latest, highest_rating, lowest_rating]
- `max_rotations` (integer, optional, default 3) — Advanced: how many times to retry a difficult request (1-6, default 3).

**Returns:** reviews[]{rating,text,author,date,source,syndicated_from}, total_reviews, page, page_size, has_more, rating, rating_count, review_count, rating_scale, rating_distribution, product_id

**Example request body:**
```json
{
  "product_id": "888140"
}
```

### POST /woolworths/v1/deals — 1 credit
woolworths.com.au's own specials pages: Half Price, Lower Shelf Price, Buy More Save More, Everyday Low Price and Seasonal Price — optionally for one department. Same rows, sorting and brand filter as search.

**Parameters:**
- `type` (enum, optional, default "half_price") — Which of woolworths.com.au's own specials pages to read. [one of: half_price, lower_shelf_price, buy_more_save_more, everyday_low_price, seasonal_price]
- `department` (string, optional) — Optional: only this department's deals — a top-level category id from `categories` (e.g. '1_717445A' Snacks & Confectionery).
- `page` (integer, optional, default 1) — Result page, 1-based. Read `count`, `total_results` and `page_count`.
- `page_size` (integer, optional, default 24) — Products per page, 1-36 (Woolworths' own maximum). Sponsored placements are on top of this and removed by default.
- `sort` (enum, optional, default "relevance") — Result order. [one of: relevance, price_asc, price_desc, name_asc, name_desc]
- `brand` (string, optional) — Only this brand, spelled exactly as in a row's `brand` (case-sensitive: 'Cadbury' works, 'cadbury' returns nothing).
- `include_sponsored` (boolean, optional, default false) — false (default) drops paid 'Promoted' placements, which Woolworths puts at fixed positions regardless of your sort; true keeps them, flagged `sponsored: true`.
- `include_ratings` (boolean, optional, default true) — true (default) adds each row's star rating and rating count (one extra lightweight lookup for the whole page).
- `max_rotations` (integer, optional, default 3) — Advanced: how many times to retry a difficult request (1-6, default 3).

**Returns:** results[]{product_id (stockcode, string), title, name, brand, package_size, barcode (EAN/GTIN), url, image, breadcrumb[]{level,id,name}, price (number, AUD — the shelf price; per kg when price_per='kg'; null when the product is unavailable), price_display, currency=AUD, original_price (the was-price, only when on special), original_price_display, savings, discount_percent, on_special, half_price, member_price (null — Woolworths published no member price to an anonymous visitor), member_unit_price_text, unit_price, unit_price_measure ('1L', '100G', '1KG', '1EA'), unit_price_text ('$1.65 / 1L'), sold_by ('piece' | 'weight'), price_per ('each' | 'kg'), increment_price, increment_grams, price_min, price_max, price_is_estimate (variable-weight packs), approx_weight_grams, multi_buy{quantity,total_price,price_each,unit_price_text,text} (never subtracted from price), availability ('in_stock' | 'unavailable' | 'not_ranged'), available, in_stock, next_available_date, max_order_quantity (an order limit, not stock), badges[]{type ('label'|'roundel'|'offer'),text,promotion}, promotion_types[], rewards_points_offer, new, online_only, marketplace, seller{type ('retailer'|'marketplace'),name,id,delivery_fee,free_shipping,dispatch_note,delivery_from,delivery_to}, has_variants, sponsored, fulfilment_store_id, rating (0-5), rating_count, review_count, rating_scale (5), rating_distribution{5,4,3,2,1}}, count, total_results, page, page_size, page_count, sponsored_dropped, filters_available{departments[]{id,name,count}, brands[]{name,value,count}}, type, department

**Example request body:**
```json
{
  "type": "half_price"
}
```

### POST /woolworths/v1/category — 1 credit
Every product in one Woolworths category (any level of the aisle tree), paged, with the same rows, sorting, specials toggle and brand filter as search, plus the category's brand list with counts.

**Parameters:**
- `category` (string, required) — A category: its id from `categories` (e.g. '1_6E4F4E4' Dairy, Eggs & Fridge, '1_B7EF010' Cheese) or its woolworths.com.au /shop/browse/… URL.
- `page` (integer, optional, default 1) — Result page, 1-based. Read `count`, `total_results` and `page_count`.
- `page_size` (integer, optional, default 24) — Products per page, 1-36 (Woolworths' own maximum). Sponsored placements are on top of this and removed by default.
- `sort` (enum, optional, default "relevance") — Result order. [one of: relevance, price_asc, price_desc, name_asc, name_desc]
- `specials_only` (boolean, optional, default false) — true = the site's own 'Specials' toggle: products on a price special AND products with a Buy More Save More multi-buy offer (`multi_buy`). Unavailable products can appear with their price hidden.
- `brand` (string, optional) — Only this brand, spelled exactly as in a row's `brand` (case-sensitive: 'Cadbury' works, 'cadbury' returns nothing).
- `include_sponsored` (boolean, optional, default false) — false (default) drops paid 'Promoted' placements, which Woolworths puts at fixed positions regardless of your sort; true keeps them, flagged `sponsored: true`.
- `include_ratings` (boolean, optional, default true) — true (default) adds each row's star rating and rating count (one extra lightweight lookup for the whole page).
- `max_rotations` (integer, optional, default 3) — Advanced: how many times to retry a difficult request (1-6, default 3).

**Returns:** results[]{product_id (stockcode, string), title, name, brand, package_size, barcode (EAN/GTIN), url, image, breadcrumb[]{level,id,name}, price (number, AUD — the shelf price; per kg when price_per='kg'; null when the product is unavailable), price_display, currency=AUD, original_price (the was-price, only when on special), original_price_display, savings, discount_percent, on_special, half_price, member_price (null — Woolworths published no member price to an anonymous visitor), member_unit_price_text, unit_price, unit_price_measure ('1L', '100G', '1KG', '1EA'), unit_price_text ('$1.65 / 1L'), sold_by ('piece' | 'weight'), price_per ('each' | 'kg'), increment_price, increment_grams, price_min, price_max, price_is_estimate (variable-weight packs), approx_weight_grams, multi_buy{quantity,total_price,price_each,unit_price_text,text} (never subtracted from price), availability ('in_stock' | 'unavailable' | 'not_ranged'), available, in_stock, next_available_date, max_order_quantity (an order limit, not stock), badges[]{type ('label'|'roundel'|'offer'),text,promotion}, promotion_types[], rewards_points_offer, new, online_only, marketplace, seller{type ('retailer'|'marketplace'),name,id,delivery_fee,free_shipping,dispatch_note,delivery_from,delivery_to}, has_variants, sponsored, fulfilment_store_id, rating (0-5), rating_count, review_count, rating_scale (5), rating_distribution{5,4,3,2,1}}, count, total_results, page, page_size, page_count, sponsored_dropped, filters_available{departments[]{id,name,count}, brands[]{name,value,count}}, category{id,name,url,parents[]}

### POST /woolworths/v1/categories — 1 credit
Woolworths' aisle tree: departments, categories and sub-categories with their ids and URLs, including the Specials groups and the Everyday Market departments.

**Parameters:**
- `depth` (integer, optional, default 2) — How many levels of the category tree to return (1-5, default 2).
- `max_rotations` (integer, optional, default 3) — Advanced: how many times to retry a difficult request (1-6, default 3).

**Returns:** categories[]{id, name, slug, url, is_special, child_count, children[]}, count, depth

### POST /woolworths/v1/suggest — 1 credit
Search-box autocomplete as a Woolworths shopper types.

**Parameters:**
- `query` (string, required) — What to look for, as a shopper would type it on woolworths.com.au ('milk', 'tim tam', 'dog food').
- `max_rotations` (integer, optional, default 3) — Advanced: how many times to retry a difficult request (1-6, default 3).

**Returns:** suggestions[], auto_corrected_query, query

**Example request body:**
```json
{
  "query": "milk"
}
```

## More
- Try it live, no code: https://reefapi.com/playground?engine=woolworths
- Human docs page: https://reefapi.com/docs/woolworths
- Overview page: https://reefapi.com/woolworths-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
