Discover/Chemist Warehouse API
live

Chemist Warehouse APIchemistwarehouse.co.nz

Access Chemist Warehouse NZ product listings, prices, ingredients, ratings, and store locations via a structured REST API with 5 endpoints.

Endpoints
5
Updated
2mo ago

What is the Chemist Warehouse API?

The Chemist Warehouse NZ API provides structured access to the New Zealand pharmacy catalog across 5 endpoints, covering product search, category browsing, detailed product data, and store locations. The get_product_details endpoint returns fields like ingredients, directions, warnings, and multiple product images, while get_store_locations can resolve stores by suburb, postcode, or lat/lng coordinates.

Try it
Page number (1-indexed)
Number of results per page
Sort option for results
Search keyword (e.g. 'vitamin c', 'panadol', 'sunscreen')
api.parse.bot/scraper/b2758f67-3cb9-4184-ab37-e3262ad57493/<endpoint>
Ready to send
Fill in the parameters and hit sign in to send to see live response data here.
Call it over HTTPgrab a free API key at signup
curl -X GET 'https://api.parse.bot/scraper/b2758f67-3cb9-4184-ab37-e3262ad57493/search_products?query=vitamin+c' \
  -H 'X-API-Key: $PARSE_API_KEY'
Python SDK · recommended

Typed, relational, agent-ready

A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.

  • Fully typed · autocompletes
  • Objects link to objects
  • Typed errors & pagination

Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:

uv add parse-sdk
uv run parse init
uv run parse add --marketplace chemistwarehouse-co-nz-api

uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.

"""
Chemist Warehouse NZ API Client
A practical example of using the Parse API to search products, browse categories,
get product details, and find store locations.

Get your API key from: https://parse.bot/settings
"""

import os
import requests
from typing import Any, Optional


class ParseClient:
    """Client for interacting with the Chemist Warehouse NZ API via Parse."""

    def __init__(self, api_key: Optional[str] = None):
        """
        Initialize the Parse API client.

        Args:
            api_key: API key for authentication. If not provided, reads from PARSE_API_KEY env var.
        """
        self.base_url = "https://api.parse.bot"
        self.scraper_id = "b2758f67-3cb9-4184-ab37-e3262ad57493"
        self.api_key = api_key or os.getenv("PARSE_API_KEY")

        if not self.api_key:
            raise ValueError(
                "API key not provided. Set PARSE_API_KEY environment variable or pass api_key parameter."
            )

    def _call(
        self, endpoint: str, method: str = "POST", **params: Any
    ) -> dict[str, Any]:
        """
        Make an API call to the Parse endpoint.

        Args:
            endpoint: The endpoint name (e.g., 'search_products')
            method: HTTP method ('GET' or 'POST')
            **params: Query/body parameters for the endpoint

        Returns:
            JSON response from the API
        """
        url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
        headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}

        if method == "GET":
            response = requests.get(url, headers=headers, params=params)
        elif method == "POST":
            response = requests.post(url, headers=headers, json=params)
        else:
            raise ValueError(f"Unsupported HTTP method: {method}")

        response.raise_for_status()
        return response.json()

    def search_products(
        self,
        query: str,
        page: int = 1,
        size: int = 48,
        sort: Optional[str] = None,
    ) -> dict[str, Any]:
        """
        Search for products by keyword.

        Args:
            query: Search keyword (e.g., 'vitamin c')
            page: Page number (1-based), default 1
            size: Number of items per page, default 48
            sort: Sort option for results

        Returns:
            Dictionary containing items, page, total, and size
        """
        params = {"query": query, "page": page, "size": size}
        if sort:
            params["sort"] = sort
        return self._call("search_products", method="GET", **params)

    def get_category_products(
        self,
        category_id: str,
        page: int = 1,
        size: int = 48,
        sort: Optional[str] = None,
    ) -> dict[str, Any]:
        """
        Get products in a specific category.

        Args:
            category_id: The numeric category ID (e.g., '81' for Vitamins)
            page: Page number (1-based), default 1
            size: Number of items per page, default 48
            sort: Sort option for results

        Returns:
            Dictionary containing items, page, total, and size
        """
        params = {"category_id": category_id, "page": page, "size": size}
        if sort:
            params["sort"] = sort
        return self._call("get_category_products", method="GET", **params)

    def get_product_details(
        self, product_id: str, slug: Optional[str] = None
    ) -> dict[str, Any]:
        """
        Get detailed information for a specific product.

        Args:
            product_id: The numeric product ID (e.g., '96405')
            slug: The product slug (optional)

        Returns:
            Dictionary containing product details including price, description, ingredients, etc.
        """
        params = {"product_id": product_id}
        if slug:
            params["slug"] = slug
        return self._call("get_product_details", method="GET", **params)

    def get_store_locations(
        self,
        search_text: Optional[str] = None,
        lat: Optional[str] = None,
        lng: Optional[str] = None,
    ) -> dict[str, Any]:
        """
        Find Chemist Warehouse store locations.

        Args:
            search_text: Search keyword (e.g., 'Auckland', postcode)
            lat: Latitude for coordinate-based search
            lng: Longitude for coordinate-based search

        Returns:
            Dictionary containing store location items
        """
        params = {}
        if search_text:
            params["search_text"] = search_text
        if lat:
            params["lat"] = lat
        if lng:
            params["lng"] = lng
        return self._call("get_store_locations", method="GET", **params)

    def get_category_list(self) -> dict[str, Any]:
        """
        Get the list of top-level product categories.

        Returns:
            Dictionary containing category items with category_id, name, and url
        """
        return self._call("get_category_list", method="GET")


def main():
    """
    Practical workflow: Search for products, get details for top results,
    explore categories, and find nearby stores.
    """
    # Initialize the client
    client = ParseClient()

    print("=" * 70)
    print("Chemist Warehouse NZ API - Practical Workflow Example")
    print("=" * 70)

    # Step 1: Search for vitamin C products
    print("\n[1] Searching for Vitamin C products...")
    search_results = client.search_products(query="vitamin c", page=1, size=5)
    
    total_found = search_results.get("total", 0)
    items = search_results.get("items", [])
    
    print(f"    ✓ Found {total_found} total products")
    print(f"    ✓ Showing {len(items)} items on page 1\n")

    # Step 2: Collect product IDs and display basic info
    print("[2] Top 3 Vitamin C Products:")
    product_ids = []
    
    for idx, product in enumerate(items[:3], 1):
        product_id = product.get("id")
        name = product.get("name", "Unknown")
        price = product.get("price_cw_nz", "N/A")
        rrp = product.get("rrp_cw_nz", "N/A")
        rating = product.get("bv_star_rating", "N/A")
        votes = product.get("bv_total_votes", "N/A")
        
        product_ids.append(product_id)
        
        print(f"\n    [{idx}] {name}")
        print(f"        Price: ${price} (RRP: ${rrp})")
        print(f"        Rating: {rating}/5 ({votes} votes)")
        print(f"        Product ID: {product_id}")

    # Step 3: Get detailed information for the first product
    if product_ids:
        print(f"\n[3] Getting detailed info for first product (ID: {product_ids[0]})...")
        
        try:
            details = client.get_product_details(product_id=product_ids[0])
            data = details.get("data", {})
            
            print(f"    ✓ Name: {data.get('name', 'N/A')}")
            print(f"    ✓ Price: {data.get('price', 'N/A')}")
            
            description = data.get("description")
            if description:
                desc_preview = description[:120] + "..." if len(description) > 120 else description
                print(f"    ✓ Description: {desc_preview}")
            
            ingredients = data.get("ingredients")
            if ingredients:
                ingredients_preview = ingredients[:100] + "..." if len(ingredients) > 100 else ingredients
                print(f"    ✓ Ingredients: {ingredients_preview}")
            
            directions = data.get("directions")
            if directions:
                directions_preview = directions[:100] + "..." if len(directions) > 100 else directions
                print(f"    ✓ Directions: {directions_preview}")
            
            images = data.get("images", [])
            if images:
                print(f"    ✓ Available {len(images)} product image(s)")
                
        except Exception as e:
            print(f"    ✗ Error fetching details: {e}")

    # Step 4: Get all categories and find Vitamins
    print("\n[4] Fetching product categories...")
    
    try:
        categories_response = client.get_category_list()
        category_items = categories_response.get("data", [])
        
        print(f"    ✓ Found {len(category_items)} categories")
        
        # Find Vitamins category
        vitamins_category_id = None
        for category in category_items:
            if "vitamin" in category.get("name", "").lower():
                vitamins_category_id = category.get("category_id")
                print(f"    ✓ Located: {category.get('name')} (ID: {vitamins_category_id})")
                break
        
        # Step 5: Get products from Vitamins category
        if vitamins_category_id:
            print(f"\n[5] Getting products from Vitamins & Supplements category...")
            category_products = client.get_category_products(
                category_id=vitamins_category_id,
                page=1,
                size=5
            )
            
            total_in_category = category_products.get("total", 0)
            items_in_category = category_products.get("items", [])
            
            print(f"    ✓ Total vitamins available: {total_in_category}")
            print(f"    ✓ Showing {len(items_in_category)} items:\n")
            
            for idx, product in enumerate(items_in_category, 1):
                name = product.get("name", "Unknown")
                price = product.get("price_cw_nz", "N/A")
                rating = product.get("bv_star_rating", "N/A")
                print(f"       {idx}. {name}")
                print(f"          Price: ${price} | Rating: {rating}/5")
                
    except Exception as e:
        print(f"    ✗ Error fetching categories: {e}")

    # Step 6: Find store locations
    print("\n[6] Finding store locations in major cities...")
    
    cities = ["Auckland", "Wellington", "Christchurch"]
    all_stores = []
    
    for city in cities:
        try:
            stores_response = client.get_store_locations(search_text=city)
            store_items = stores_response.get("data", [])
            
            if store_items:
                print(f"    ✓ {city}: Found {len(store_items)} store(s)")
                all_stores.append(store_items[0])  # Keep first store from each city
                
        except Exception as e:
            print(f"    ✗ Error finding stores in {city}: {e}")
    
    # Display store details
    if all_stores:
        print("\n[7] Nearby Store Details:")
        for idx, store in enumerate(all_stores, 1):
            print(f"\n    [{idx}] {store.get('name', 'Unknown Store')}")
            print(f"        Address: {store.get('address', 'N/A')}")
            print(f"        Suburb: {store.get('suburb', 'N/A')} {store.get('postcode', '')}")
            print(f"        Phone: {store.get('phone', 'N/A')}")
            if store.get('email'):
                print(f"        Email: {store.get('email')}")

    print("\n" + "=" * 70)
    print("✓ Workflow completed successfully!")
    print("=" * 70)


if __name__ == "__main__":
    main()
All endpoints · 5 totalmissing one? ·

Search for products by keyword. Returns paginated product listings with prices, ratings, and thumbnails from the Chemist Warehouse NZ catalog.

Input
ParamTypeDescription
pageintegerPage number (1-indexed)
sizeintegerNumber of results per page
sortstringSort option for results
queryrequiredstringSearch keyword (e.g. 'vitamin c', 'panadol', 'sunscreen')
Response
{
  "type": "object",
  "fields": {
    "page": "integer current page number",
    "size": "integer page size",
    "items": "array of product objects with id, name, price_cw_nz, rrp_cw_nz, bv_star_rating, bv_total_votes, producturl, _thumburl",
    "total": "integer total number of matching products"
  },
  "sample": {
    "data": {
      "page": 1,
      "size": 48,
      "items": [
        {
          "id": "96405",
          "name": "Healtheries Vitamin C 1,000mg + Prebiotics & Probiotics 80 Tablets",
          "_thumburl": "https://static.chemistwarehouse.co.nz/ams/media/pi/96405/2DF_200.jpg",
          "rrp_cw_nz": "30.5",
          "price_cw_nz": "18.99",
          "bv_star_rating": "4.4737",
          "bv_total_votes": "38"
        }
      ],
      "total": 222
    },
    "status": "success"
  }
}

About the Chemist Warehouse API

Product Search and Category Browsing

The search_products endpoint accepts a query string (e.g. 'vitamin c', 'panadol') and returns paginated results including price_cw_nz, rrp_cw_nz, bv_star_rating, bv_total_votes, and a _thumburl thumbnail per product. Pagination is controlled via page and size parameters, and results can be ordered using the sort parameter. The total field in the response tells you how many matching products exist across all pages.

To browse by category rather than keyword, use get_category_list first — it returns each category's name, url, and category_id. Pass that category_id to get_category_products to retrieve paginated listings in the same shape as search results. This two-step pattern lets you iterate across the full catalog without needing a keyword.

Product Detail

The get_product_details endpoint takes a product_id (obtained from search or category listing responses) and returns a richer data shape: description, ingredients, directions, warnings, general_info, a formatted price string, and an images array of full-size image URLs. Fields that the product page does not populate are returned as null rather than omitted, so you can handle them consistently. An optional slug parameter supports cleaner URL construction but does not affect the data returned.

Store Locations

The get_store_locations endpoint accepts either a search_text value (city, suburb, or postcode such as 'Auckland' or '1010') or a lat/lng coordinate pair. It returns matching stores with name, address, suburb, postcode, phone, email, latitude, and longitude. Results are sorted by distance from the input location.

Reliability & maintenance

The Chemist Warehouse API is a managed, monitored endpoint for chemistwarehouse.co.nz — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when chemistwarehouse.co.nz changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.

This isn't an official chemistwarehouse.co.nz API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.

Will this API break when the source site changes?+
It's built not to. Every endpoint is health-checked on a schedule with automated test probes. When the source site changes and a check fails, the API is automatically queued for repair and re-verified — that's the self-healing layer. Each API page shows when its endpoints were last verified. And because marketplace APIs are shared, any fix reaches everyone using it.
Is this an official API from the source site?+
No — Parse APIs are independent, managed REST wrappers over publicly available data. That is the point: where a site has no official API (or only a limited one), Parse gives you a maintained, monitored endpoint for that data and keeps it working as the site changes — so you get a stable contract over a source that never promised one.
Can I fix or extend this API myself if I need a new endpoint or field?+
Yes — and you don't have to wait on us. This API was generated by the Parse agent, which stays attached. Describe the change in plain English ("add an endpoint that returns reviews", "fix the price field") in the revise box on the API page or via the revise_api MCP tool, and the agent rebuilds it against the live site in minutes. Contributing the change back to the public API is free.
What happens if I call an endpoint that has an issue?+
Errors are machine-readable: a bad call returns a clean status with the list of available endpoints and a repair hint, so an agent (or you) can recover or trigger a fix instead of failing silently. Confirmed failures feed the automatic repair queue.
Common use cases
  • Compare price_cw_nz vs rrp_cw_nz across a category to identify discounted products
  • Build a medication finder that surfaces warnings and directions for a given drug name
  • Aggregate bv_star_rating and bv_total_votes across supplement categories for review analysis
  • Construct a store locator feature using get_store_locations with device GPS coordinates
  • Export full ingredient lists via get_product_details for nutritional or allergen comparison tools
  • Index the entire NZ pharmacy catalog by walking get_category_list and paginating get_category_products
  • Monitor price changes for specific product IDs by polling get_product_details over time
Pricing & limitsSee full pricing →
TierPriceCredits/monthRate limit
Free$0/mo1005 req/min
Hobby$30/mo1,00020 req/min
Developer$100/mo5,000100 req/min

One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.

Frequently asked questions
Does Chemist Warehouse NZ have an official developer API?+
Chemist Warehouse NZ does not publish a documented public developer API for third-party use. This Parse API provides structured access to the product and store data available on chemistwarehouse.co.nz.
What does `get_product_details` return that the listing endpoints don't?+
The listing endpoints (search_products, get_category_products) return summary fields: id, name, price_cw_nz, rrp_cw_nz, bv_star_rating, bv_total_votes, producturl, and _thumburl. The get_product_details endpoint adds description, ingredients, directions, warnings, general_info, a formatted price string, and a full images array. Fields not present on the product page are returned as null.
Can I search for products within a specific price range?+
The search_products and get_category_products endpoints do not currently accept price-range filter parameters — filtering is limited to query, sort, page, and size. You can retrieve paginated results and apply price filtering client-side using the price_cw_nz field. You can also fork this API on Parse and revise it to add a price-filter parameter if the underlying data supports it.
Does the API cover Chemist Warehouse Australia or only New Zealand?+
This API covers the New Zealand site (chemistwarehouse.co.nz) only. Prices and product availability reflect the NZ catalog. Chemist Warehouse Australia is a separate site with its own inventory. You can fork this API on Parse and revise it to point at the Australian domain to add that coverage.
Are product stock levels or availability returned?+
Stock levels and in-store availability are not currently included in any response field across the 5 endpoints. The API returns pricing, ratings, product detail text, and store contact information. You can fork this API on Parse and revise it to add a stock-availability endpoint if that data is exposed on the product pages.
Page content last updated . Spec covers 5 endpoints from chemistwarehouse.co.nz.
Related APIs in EcommerceSee all →
dischem.co.za API
Search for pharmacy products and retrieve detailed information including prices, descriptions, and images directly from Dis-Chem's catalog. Browse product listings and access complete product details all in one place.
walmart.ca API
Search Walmart Canada products and retrieve detailed information like prices, availability, and specifications. Find nearby Walmart pharmacy locations to check services and hours.
cvs.com API
Find nearby CVS Pharmacy locations and check their hours, then search for products and verify real-time availability at specific stores. Quickly locate what you need and confirm it's in stock before making a trip.
aponeo.de API
Search for medications and health products from Aponeo.de, view detailed pricing and availability, browse by category, and discover current deals and promotions. Find specific products by PZN code, check bestsellers, or explore newly added items to compare prices and stock status.
costco.com API
Search and browse Costco's complete product catalog, retrieve detailed product information and member reviews, check current savings and promotions, and find nearby warehouse locations — all through a single API.
apollo247.com API
Search and compare medicines, view detailed product information, discover lab tests, and locate nearby Apollo 24|7 pharmacy stores. Browse medical specialties and popular diagnostic services to plan your healthcare needs in one convenient platform.
pharmdata.co.uk API
Search UK pharmacies, access NHS service statistics, and retrieve pharmacy dispensing data to compare performance across regions. Monitor MHRA drug safety alerts and view LPC rankings to make informed decisions about pharmacy services and medications.
theordinary.com API
Browse and search The Ordinary's complete product catalog by category or ingredients. View detailed product information including formulas and key actives, apply filters by product type, concern, or ingredient, and read customer reviews to compare and evaluate products.