{
  "openapi": "3.0.1",
  "info": {
    "title": "Dan Murphy’s Scraper - Prices, Stock, Ratings & Specials",
    "description": "Scrape Dan Murphy’s products by category, keyword, or specials. Extract 45+ fields, including regular, sale and member prices, case and unit pricing, stock, ratings, reviews, country, variety, and ABV. Incremental mode tracks changes.",
    "version": "1.1",
    "x-build-id": "h9ZXFDfuj7nMAvrgL"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~danmurphys-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-danmurphys-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/abotapi~danmurphys-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-danmurphys-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/abotapi~danmurphys-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-danmurphys-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "url"
            ],
            "type": "string",
            "description": "Search mode walks a department (optionally a sub-department, a keyword, a brand, specials-only). URL mode walks any category route or product link you paste — multiple allowed, pagination walks forward automatically."
          },
          "department": {
            "title": "Department",
            "enum": [
              "beer",
              "red-wine",
              "white-wine",
              "champagne-sparkling",
              "spirits",
              "whisky",
              "fortified-wine",
              "premix",
              "other-drinks",
              "zero-alcohol-drinks",
              "accessories",
              "food-snacks",
              "gifts"
            ],
            "type": "string",
            "description": "Department route. Beer, spirits, whisky, accessories and gifts answer today; the site's backend currently rejects several others (the wine, premix, other-drinks, zero-alcohol and food routes answer 'Category does not exist'). A rejected department is reported in the run log, and a run where every scope was rejected fails with that message instead of finishing empty. Keep the enum values: the site may re-enable them."
          },
          "subDepartment": {
            "title": "Sub-department (optional)",
            "type": "string",
            "description": "Sub-department name, matched case-insensitively against the department's own list (e.g. 'Craft Beer' or 'craft-beer' for /beer/craft-beer, 'Scotch Whisky' for /whisky/scotch-whisky, 'Vodka' for /spirits/vodka). A name that matches nothing stops that scope with an error listing the valid values. Leave empty for the whole department."
          },
          "searchTerm": {
            "title": "Keyword search (optional)",
            "type": "string",
            "description": "Free-text search. If given, a keyword scope runs in addition to the department scope."
          },
          "brand": {
            "title": "Brand filter (optional)",
            "type": "string",
            "description": "Brand name or slug, matched case-insensitively against the department's brand list ('Stone & Wood' or 'stone-and-wood', '4 Pines'). A brand that matches nothing stops that scope with an error listing the valid brands; it is never silently ignored. Search mode only."
          },
          "urls": {
            "title": "Category / product URLs",
            "type": "array",
            "description": "Category routes (/beer/craft-beer, /whisky/scotch-whisky, /spirits) and/or product links (/product/{code}/{name}). Multi-URL supported. Pagination starts at the pasted URL's first page and walks forward. The specials, member-offers, price and facet filters in the next section apply to category URLs too. Search links (/search?searchTerm=...) run a keyword scope; if the site answers the term with a category or style page, that page is walked instead. A link the site rejects is reported in the run log. A ?page=N suffix is not used (the walk starts at page 1). Left untouched in url mode, the five example links are scraped (a sub-department, a multi-word sub-department, a department, a department /all link and a product link).",
            "default": [
              "https://www.danmurphys.com.au/beer/craft-beer",
              "https://www.danmurphys.com.au/whisky/scotch-whisky",
              "https://www.danmurphys.com.au/spirits",
              "https://www.danmurphys.com.au/whisky/all",
              "https://www.danmurphys.com.au/product/DM_560632/balter-xpa-cans-375ml"
            ],
            "items": {
              "type": "string"
            }
          },
          "specialsOnly": {
            "title": "Specials only",
            "type": "boolean",
            "description": "Only products with a current offer (the site's currentoffer facet). Applies to the department scope in search mode and to every category URL in url mode (not to the keyword search or pasted product links).",
            "default": false
          },
          "memberOffersOnly": {
            "title": "Member offers only",
            "type": "boolean",
            "description": "Only products carrying a member (My Dan Murphy's) offer. Applies to the department scope in search mode and to every category URL in url mode (not to the keyword search or pasted product links).",
            "default": false
          },
          "minPrice": {
            "title": "Minimum price (AUD)",
            "minimum": 0,
            "type": "number",
            "description": "Only products priced at or above this amount (the site's native price filter). Leave empty for no lower bound. Applies to search mode and to every URL in url mode."
          },
          "maxPrice": {
            "title": "Maximum price (AUD)",
            "minimum": 0,
            "type": "number",
            "description": "Only products priced at or below this amount. Leave empty for no upper bound."
          },
          "country": {
            "title": "Country (optional)",
            "type": "string",
            "description": "Country of origin, matched case-insensitively against the site's own country facet (e.g. 'Australia'). Comma-separated for several. Applies to the department scope, the keyword scope and every category URL."
          },
          "region": {
            "title": "Region (optional)",
            "type": "string",
            "description": "Region facet, matched case-insensitively against what the site offers for that department (e.g. 'Geelong'). Comma-separated for several."
          },
          "style": {
            "title": "Style (optional)",
            "type": "string",
            "description": "Style facet of the department (beer style such as 'IPA' or 'Pale Ale', whisky style, ...), matched case-insensitively. Comma-separated for several."
          },
          "variety": {
            "title": "Variety / type (optional)",
            "type": "string",
            "description": "The site's variety facet, which lists the department's types (e.g. 'Craft Beer', 'Scotch Whisky'). Same list as the sub-department, applied as a filter. Comma-separated for several."
          },
          "sortBy": {
            "title": "Sort order",
            "enum": [
              "Relevance",
              "Name",
              "PriceAsc",
              "PriceDesc"
            ],
            "type": "string",
            "description": "Native site sort applied to every scope. With a small Max products this selects the cheapest / most expensive items.",
            "default": "Relevance"
          },
          "fetchDetails": {
            "title": "Fetch product details (charged per product)",
            "type": "boolean",
            "description": "Fetch each pushed product's detail payload (tasting/rich description, recommendations). Adds a per-product surcharge — see pricing. Listing tiles already carry prices, member offers, ratings, stock and attributes without this.",
            "default": false
          },
          "maxPages": {
            "title": "Max pages per scope (0 = unlimited)",
            "minimum": 0,
            "type": "integer",
            "description": "Cap on pages walked per scope. 0 walks until the department is exhausted.",
            "default": 0
          },
          "maxProducts": {
            "title": "Max products per scope (0 = unlimited)",
            "minimum": 0,
            "type": "integer",
            "description": "Cap on products scanned, applied to each scope separately (the keyword search, the department and every pasted category link each get their own allowance; pasted product links are not counted). Default 20. 0 = unlimited (a full department can be tens of thousands of products).",
            "default": 20
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify proxy. The default Apify datacenter proxy works for this site; if you see blocks, switch to Apify Residential with country AU. Apify free plans do not include proxy access: on such a plan the run continues on a backup connection where possible and may still return nothing, so supply your own proxy URLs or use a plan with proxy access."
          },
          "resumeFromRunId": {
            "title": "Resume from run (optional)",
            "type": "string",
            "description": "Continue ONE interrupted run: products already collected by that run are skipped. Cannot be combined with incremental mode."
          },
          "incrementalMode": {
            "title": "Incremental mode (recurring monitoring)",
            "type": "boolean",
            "description": "For scheduled monitoring: the run remembers the previous run of the SAME search and classifies every product NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED. Compared: every output field (price, was price, special and member-offer flags, case/single/any-six prices, stock quantity, purchasable/delivery flags, name, description, ratings, images...). Never compared: scrapedAt, categoryUrl (the link a row was collected from) and the detail-enrichment flags, plus anything listed in 'Ignore fields when detecting changes'. Defaults off — no existing user's runs change until they opt in.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode)",
            "type": "string",
            "description": "Manual key for the incremental baseline. Leave empty to auto-key on mode + department + filters, so two different filter setups never share a baseline."
          },
          "emitUnchanged": {
            "title": "Emit unchanged products",
            "type": "boolean",
            "description": "Incremental mode only. Also return (and bill) products classified UNCHANGED.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired products",
            "type": "boolean",
            "description": "Incremental mode only. Also return (and bill) products that vanished since the last complete run. When Max products is above 0 the EXPIRED rows are limited to Max products minus the rows already pushed in the run.",
            "default": false
          },
          "changeScope": {
            "title": "Change scope (incremental mode only)",
            "enum": [
              "all",
              "priceAndStock"
            ],
            "type": "string",
            "description": "Incremental mode only. 'all' compares every field except the volatile ones. 'priceAndStock' marks a product UPDATED only when its price, was-price, special/member-offer flags, case/single/any-six prices, stock quantity or purchasable/delivery flags move; descriptions, images and labels never create an UPDATED row. Changing this under an auto state key starts a fresh baseline; use a State key to keep one.",
            "default": "all"
          },
          "compactUpdates": {
            "title": "Compact UPDATED rows (incremental mode only)",
            "type": "boolean",
            "description": "Incremental mode only. UPDATED and EXPIRED rows carry only ids, url, name, current price/stock and priceChanges {field: {old, new}} instead of the full record. NEW rows stay full. Compact UPDATED rows skip detail enrichment, so they carry no detail-enrichment charge.",
            "default": false
          },
          "expireAfterMissedScans": {
            "title": "Expire after N missed scans (incremental mode only)",
            "minimum": 1,
            "type": "integer",
            "description": "Incremental mode only, with 'Emit expired products'. A product is marked EXPIRED only after it was missing from this many consecutive complete scans (1 = the first). EXPIRED means the product dropped out of the scanned listing; without a detail check a listing drop and a delisting look the same, so use the stock fields (stockQty, purchasable) for availability.",
            "default": 1
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Incremental mode only. Field names to leave out when deciding whether a product changed (kept in the output, excluded from the comparison and from changedFields). Dotted paths such as variations.image drop that key from every array element. scrapedAt, categoryUrl and the detail-enrichment flags are always ignored.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "MCP connectors",
            "type": "array",
            "description": "Connector ids (authorized under Apify → Settings → Integrations) to push results into — Notion and compatible MCP targets. Optional.",
            "items": {
              "type": "string"
            }
          },
          "notionParentPageUrl": {
            "title": "Notion parent page URL",
            "type": "string",
            "description": "For a Notion MCP connector: the parent page the results are written under. Optional."
          },
          "maxNotifyListings": {
            "title": "Max items sent to connectors",
            "minimum": 0,
            "type": "integer",
            "description": "Cap on items exported to connectors per run. 0 exports everything pushed.",
            "default": 0
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}