# Bunnings API scraper — Australia's and New Zealand's #1 hardware and home-improvement retailer (bunnings.com.au, bunnings.co.nz): store-priced search and category browse, full product records, marketplace sellers, per-store stock with aisle and bay, the store finder and search suggestions. No account, no browser.

> Search Bunnings by keyword, priced for one store (prices differ by region). Filters: brand, price range, minimum rating, fulfilment option, offer badge, Bunnings vs Marketplace seller, special order, category. Each row: item number, title, brand, store price, unit price, marketplace seller, fulfilment options, offer badges and campaign, key selling points, the search-index rating and review count, variant count, image, URL and category path.
> ReefAPI engine `bunnings` · 6 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/bunnings/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 /bunnings/v1/search — 1 credit
Search Bunnings by keyword, priced for one store (prices differ by region). Filters: brand, price range, minimum rating, fulfilment option, offer badge, Bunnings vs Marketplace seller, special order, category. Each row: item number, title, brand, store price, unit price, marketplace seller, fulfilment options, offer badges and campaign, key selling points, the search-index rating and review count, variant count, image, URL and category path.

**Parameters:**
- `query` (string, required) — Search keyword(s).
- `country` (enum, optional, default "au") — Bunnings storefront. Currency follows it (AUD / NZD). [one of: au, nz]
- `store_id` (string, optional) — Bunnings store number (from the stores action). Prices, stock and aisle locations are store-bound. Default: the site's own default store (AU 6400 Mentone VIC, NZ 9489).
- `postcode` (string, optional) — 4-digit postcode; the store Bunnings assigns to it is used (instead of store_id).
- `page` (integer, optional, default 1) — Result page (1-based).
- `per_page` (integer, optional, default 36) — Rows per page (Bunnings' own page is 36; max 60).
- `sort` (enum, optional, default "relevance") — Result order (each one is Bunnings' own sort). [one of: relevance, price_asc, price_desc, rating, name_asc, name_desc, newest]
- `brand` (string, optional) — Only this brand (Bunnings' brand name, case-insensitive).
- `price_min` (number, optional) — Lowest store price.
- `price_max` (number, optional) — Highest store price.
- `min_rating` (number, optional) — Minimum star rating (0-5).
- `fulfilment` (enum, optional) — Only products offered this way at the chosen store. [one of: click_and_collect, delivery, in_store]
- `offer` (enum, optional) — Only products carrying this Bunnings offer badge. [one of: new_arrival, redemption_offer, the_block, delivery_included, custom_made, fsc_certified]
- `seller` (enum, optional) — Bunnings' own range, Bunnings Marketplace third-party sellers, or both. Default follows the site: AU shows both, NZ shows Bunnings' range only. [one of: all, bunnings, marketplace]
- `special_order` (boolean, optional) — true = only special-order products; false = exclude them.
- `category` (string, optional) — Restrict to a category code (e.g. drills) or category URL.
- `include_fallback_results` (boolean, optional, default false) — When no row on the page contains a query word, the rows are dropped as unrelated padding; true returns them in fallback_results.
- `live_prices` (boolean, optional, default false) — Search rows carry the price Bunnings' search grid shows (its search index), which can lag the product page (2 of 84 rows measured). true re-prices every row from the live product price (one extra small request per row); rows then say price_source=live and keep search_index_price when it differed.

**Returns:** results[]{position, item_number, title, brand, brand_code, url, price, price_source (search_index | live), search_index_price (only when live_prices re-priced a differing row), currency, unit_price{price, unit, unit_code, item_quantity}, sold_by_unit, is_marketplace, seller{name, trusted_seller}, fulfilment_options[], is_special_order, delivery_included, promotions[], campaign{id, starts, ends, onepass_exclusive}, key_selling_points[], search_index_rating, search_index_review_count, rating_scale, variant_count, colour_count, new_arrival, best_seller, age_restricted, for_hire, image, thumbnail, category_path[{code, name, path}]}, count, total_results, page, per_page, has_more, store{store_id, name, pricing_region, chosen_by}, country, currency, query, sort, did_you_mean, site_redirect{url, category_code}, fallback_results_dropped, fallback_results[] (only with include_fallback_results=true), duplicate_rows_dropped, live_price_changes (only with live_prices=true), page_notice

**Example request body:**
```json
{
  "query": "cordless drill"
}
```

### POST /bunnings/v1/category/products — 1 credit
Browse a Bunnings category (any level, from 'tools' down to 'cordless-drill-kits') with the same store pricing, sorts and filters as search.

**Parameters:**
- `category` (string, required) — Category code (last part of the category URL, e.g. cordless-drill-kits) or a bunnings.com.au / bunnings.co.nz /products/… category URL.
- `country` (enum, optional, default "au") — Bunnings storefront. Currency follows it (AUD / NZD). [one of: au, nz]
- `store_id` (string, optional) — Bunnings store number (from the stores action). Prices, stock and aisle locations are store-bound. Default: the site's own default store (AU 6400 Mentone VIC, NZ 9489).
- `postcode` (string, optional) — 4-digit postcode; the store Bunnings assigns to it is used (instead of store_id).
- `page` (integer, optional, default 1) — Result page (1-based).
- `per_page` (integer, optional, default 36) — Rows per page (Bunnings' own page is 36; max 60).
- `sort` (enum, optional, default "relevance") — Result order (each one is Bunnings' own sort). [one of: relevance, price_asc, price_desc, rating, name_asc, name_desc, newest]
- `brand` (string, optional) — Only this brand (Bunnings' brand name, case-insensitive).
- `price_min` (number, optional) — Lowest store price.
- `price_max` (number, optional) — Highest store price.
- `min_rating` (number, optional) — Minimum star rating (0-5).
- `fulfilment` (enum, optional) — Only products offered this way at the chosen store. [one of: click_and_collect, delivery, in_store]
- `offer` (enum, optional) — Only products carrying this Bunnings offer badge. [one of: new_arrival, redemption_offer, the_block, delivery_included, custom_made, fsc_certified]
- `seller` (enum, optional) — Bunnings' own range, Bunnings Marketplace third-party sellers, or both. Default follows the site: AU shows both, NZ shows Bunnings' range only. [one of: all, bunnings, marketplace]
- `special_order` (boolean, optional) — true = only special-order products; false = exclude them.
- `live_prices` (boolean, optional, default false) — Search rows carry the price Bunnings' search grid shows (its search index), which can lag the product page (2 of 84 rows measured). true re-prices every row from the live product price (one extra small request per row); rows then say price_source=live and keep search_index_price when it differed.

**Returns:** results[] (same row shape as search), count, total_results, page, per_page, has_more, category{code, name, path}, store{…}, country, currency, sort

### POST /bunnings/v1/product/detail — 1 credit
The full Bunnings product record for one store: title, brand, model number, store price, unit price, Afterpay/PayPal instalments, availability (delivery, click & collect and in-store stock with aisle and bay), rating and review count, description, key features, the spec table, dimensions and weight, images, manuals, breadcrumb, variants, offer badges and campaign, warranty, and for Bunnings Marketplace listings every seller's offer with the featured one marked.

**Parameters:**
- `item_number` (string, required) — Bunnings item number (I/N, e.g. 0539753) or a product URL (…_p0539753).
- `country` (enum, optional, default "au") — Bunnings storefront. Currency follows it (AUD / NZD). [one of: au, nz]
- `store_id` (string, optional) — Bunnings store number (from the stores action). Prices, stock and aisle locations are store-bound. Default: the site's own default store (AU 6400 Mentone VIC, NZ 9489).
- `postcode` (string, optional) — 4-digit postcode; the store Bunnings assigns to it is used (instead of store_id).

**Returns:** product{item_number, title, brand, brand_code, model_number, model_name, gtin (null — not published), manufacturer, url, price, currency, was_price (null — not published), member_price (null), unit_price{price, unit, unit_code, item_quantity}, instalments, availability, fulfilment{store_id, store_name, in_store{available, stock, stock_status, aisle_locations[{aisle, bay}], store_map_url}, click_and_collect{available, stock, stock_status, collect_from}, delivery{available, delivery_included, stock, stock_status, message_code}, is_special_order, add_to_cart_enabled, stock_hidden_by_site}, rating, review_count, rating_scale, is_marketplace, seller{id, name}, offers[{offer_id, seller{id, name}, price, shipping_price, total_price, currency, delivery_from, delivery_to, is_featured}], featured_offer_id, cheapest_offer_price, has_multiple_offers, description, key_features[], specs[{name, value}], dimensions{product[], package[]}, weight_kg, images[], documents[{type, url, size_bytes}], breadcrumb[{code, name, path}], variants[{item_number, options, colour, url, is_current}], promotions[], campaign{…}, warranty, delivery_information, safety_information, flags{…}}, store{…}, country

**Example request body:**
```json
{
  "item_number": "0539753"
}
```

### POST /bunnings/v1/product/stock — 2 credits
In-store stock, click & collect, the aisle and bay, and the store price for one item across several Bunnings stores: pass store_ids, or a postcode / latitude+longitude to check the nearest stores.

**Parameters:**
- `item_number` (string, required) — Bunnings item number (I/N, e.g. 0539753) or a product URL (…_p0539753).
- `country` (enum, optional, default "au") — Bunnings storefront. Currency follows it (AUD / NZD). [one of: au, nz]
- `store_ids` (array, optional) — Up to 10 store numbers to check (comma-separated). Or use postcode / latitude+longitude to check the nearest stores.
- `postcode` (string, optional) — 4-digit postcode; the store Bunnings assigns to it is used (instead of store_id).
- `latitude` (number, optional) — Latitude (with longitude) to find the nearest stores.
- `longitude` (number, optional) — Longitude (with latitude).
- `nearest` (integer, optional, default 5) — How many nearest stores to check when postcode or latitude/longitude is given.

**Returns:** item_number, title, stores[{store_id, name, suburb, state, distance_km, price, currency, unit_price, availability, in_store{available, stock, stock_status, aisle_locations[], store_map_url}, click_and_collect{…}, delivery{…}, is_special_order}], count, in_stock_store_count, country

**Example request body:**
```json
{
  "item_number": "0539753"
}
```

### POST /bunnings/v1/stores — 1 credit
The Bunnings store finder: stores nearest a postcode or latitude/longitude (20 per page), or one store by id — address, phone, coordinates, distance, opening hours, services, click & collect and drive & collect flags, and the pricing region.

**Parameters:**
- `country` (enum, optional, default "au") — Bunnings storefront. Currency follows it (AUD / NZD). [one of: au, nz]
- `postcode` (string, optional) — 4-digit postcode; the store Bunnings assigns to it is used (instead of store_id).
- `latitude` (number, optional) — Latitude (with longitude) to find the nearest stores.
- `longitude` (number, optional) — Longitude (with latitude).
- `store_id` (string, optional) — One store by number (returns opening hours and services).
- `page` (integer, optional, default 1) — Page of stores (20 per page, nearest first).

**Returns:** stores[{store_id, name, address, address_line2, suburb, state, postcode, country, phone, email, latitude, longitude, distance_km, store_type, pricing_region, time_zone, has_click_and_collect, has_delivery, has_drive_and_collect, is_active, opening_hours[{day, open, close, closed}] (store_id lookups), services[] (store_id lookups), store_map_url}], count, total_stores, page, has_more, origin{latitude, longitude, postcode}, country

**Example request body:**
```json
{
  "postcode": "2000"
}
```

### POST /bunnings/v1/search/suggest — 1 credit
Bunnings' search-box suggestions for a partial keyword.

**Parameters:**
- `query` (string, required) — Partial keyword typed into the search box.
- `country` (enum, optional, default "au") — Bunnings storefront. Currency follows it (AUD / NZD). [one of: au, nz]
- `store_id` (string, optional) — Bunnings store number (from the stores action). Prices, stock and aisle locations are store-bound. Default: the site's own default store (AU 6400 Mentone VIC, NZ 9489).

**Returns:** suggestions[{text, score}], count, query, country

**Example request body:**
```json
{
  "query": "cordless drill"
}
```

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