{
  "openapi": "3.0.1",
  "info": {
    "title": "ALDI Scraper — Grocery Prices, 14 Countries",
    "description": "Scrape ALDI grocery products and prices across 14 countries — the UK, Ireland, Germany, Austria, Switzerland, Italy, Slovenia, Hungary, Australia, the Netherlands, Belgium, France, Spain and Poland. Every row carries the shelf price, the per-unit comparison price and pack size.",
    "version": "0.2",
    "x-build-id": "ww01sfSX2HasNeQ4w"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/blackfalcondata~aldi-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-blackfalcondata-aldi-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/blackfalcondata~aldi-scraper/runs": {
      "post": {
        "operationId": "runs-sync-blackfalcondata-aldi-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/blackfalcondata~aldi-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-blackfalcondata-aldi-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",
        "properties": {
          "query": {
            "title": "🔍 Search Term(s)",
            "type": "string",
            "description": "Product search keywords, e.g. \"milk\", \"coffee\", \"chocolate\". Paste a JSON array like [\"milk\",\"coffee\"] to run several searches in one go. Leave empty to walk the market's entire assortment."
          },
          "categories": {
            "title": "🗂️ Categories",
            "type": "array",
            "description": "Limit to categories, by name as shown on the storefront (e.g. [\"Chilled Food\",\"Bakery\"]). Names are matched against that market's own category list; anything unmatched is reported and ignored rather than silently widening the run. Leave empty for the whole assortment.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "brands": {
            "title": "🏷️ Brands",
            "type": "array",
            "description": "Limit to ALDI own-label or supplier brands, by name (e.g. [\"COWBELLE\",\"BARISSIMO\"]). Leave empty for all brands.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "themes": {
            "title": "✨ Themes",
            "type": "array",
            "description": "Limit to storefront themes — the seasonal and Specialbuys-style groupings (e.g. [\"Beauty\",\"Outdoor\"]). Leave empty for all.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "sortBy": {
            "title": "↕️ Sort By",
            "enum": [
              "relevance",
              "price_asc",
              "price_desc",
              "name_asc",
              "name_desc"
            ],
            "type": "string",
            "description": "Order the storefront returns products in. Matters when you cap the run: price_asc with Max Results 100 gives the 100 cheapest products, not an arbitrary 100."
          },
          "onSaleOnly": {
            "title": "🔖 Reduced Products Only",
            "type": "boolean",
            "description": "Keep only products showing a struck-through was-price.",
            "default": false
          },
          "minPrice": {
            "title": "💰 Min Price",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only products at or above this shelf price, in the market's own currency."
          },
          "maxPrice": {
            "title": "💰 Max Price",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only products at or below this shelf price, in the market's own currency."
          },
          "includeUpcomingOffers": {
            "title": "📅 Upcoming Promotions",
            "type": "boolean",
            "description": "Scrape the dated promotion pages instead of the catalogue, for every date the market publishes from today onward. ALDI announces promotions up to two weeks ahead, so this returns prices that are not on the shelf yet.",
            "default": false
          },
          "offerDates": {
            "title": "📅 Specific Promotion Dates",
            "type": "array",
            "description": "Scrape specific promotion dates (YYYY-MM-DD), e.g. [\"2026-08-06\"]. Combines with Upcoming Promotions. Leave empty to scrape the catalogue instead.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "startUrls": {
            "title": "🔗 Start URLs",
            "type": "array",
            "description": "Paste product-listing or category URLs from the ALDI storefront. Each URL becomes its own task; results are merged and deduped by product across all URLs. When provided AND parseable, start URLs replace the search term and market fields.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "countries": {
            "title": "🌍 Markets",
            "type": "array",
            "description": "Countries to scrape — pick \"All countries\" for every market at once. Several can be combined to compare the same product across borders in one run; every row is tagged with its country, retail banner and currency. ALDI is two separate companies with separate assortments and separate prices, and Germany is served by BOTH: picking Germany returns the northern and southern ranges, each row labelled with the banner that sells it. Use the banner filter below to take only one. Clear this field entirely and the run stops immediately without scraping anything.",
            "items": {
              "type": "string",
              "enum": [
                "ALL",
                "GB",
                "IE",
                "DE",
                "AT",
                "CH",
                "IT",
                "SI",
                "HU",
                "AU",
                "NL",
                "BE",
                "ES",
                "PL",
                "FR"
              ],
              "enumTitles": [
                "🌍 All countries (14)",
                "United Kingdom (ALDI)",
                "Ireland (ALDI)",
                "Germany (ALDI NORD + ALDI SÜD)",
                "Austria (HOFER)",
                "Switzerland (ALDI SUISSE)",
                "Italy (ALDI)",
                "Slovenia (HOFER)",
                "Hungary (ALDI)",
                "Australia (ALDI)",
                "Netherlands (ALDI)",
                "Belgium (ALDI)",
                "Spain (ALDI)",
                "Poland (ALDI)",
                "France (ALDI)"
              ]
            }
          },
          "banners": {
            "title": "🏳️ Banner",
            "type": "array",
            "description": "Optional. Keep only products sold under these retail banners. Mostly useful for Germany, where ALDI NORD and ALDI SÜD each serve half the country with different ranges and different prices — leave empty to get both.",
            "items": {
              "type": "string",
              "enum": [
                "ALDI",
                "ALDI NORD",
                "ALDI SÜD",
                "HOFER",
                "ALDI SUISSE"
              ],
              "enumTitles": [
                "ALDI (most markets)",
                "ALDI NORD (northern Germany)",
                "ALDI SÜD (southern Germany)",
                "HOFER (Austria, Slovenia)",
                "ALDI SUISSE (Switzerland)"
              ]
            }
          },
          "companies": {
            "title": "🏢 Company",
            "type": "array",
            "description": "Optional. ALDI is two independent companies. Pick one to scrape only its markets: ALDI SÜD covers the UK, Ireland, southern Germany, Austria, Switzerland, Italy, Slovenia, Hungary and Australia; ALDI NORD covers the Netherlands, Belgium, northern Germany, France, Spain and Poland. Leave empty for both. This is the operating company, not the shop sign — most of these markets trade under a plain \"ALDI\" banner, so the banner filter below cannot express \"all of one company\".",
            "items": {
              "type": "string",
              "enum": [
                "ALDI SÜD",
                "ALDI NORD"
              ],
              "enumTitles": [
                "ALDI SÜD (9 markets)",
                "ALDI NORD (6 markets)"
              ]
            }
          },
          "maxResults": {
            "title": "💯 Max Results",
            "minimum": 0,
            "maximum": 5000,
            "type": "integer",
            "description": "Maximum total products (0 = unlimited). The largest market lists about 3,700 products.",
            "default": 25
          },
          "includeDetails": {
            "title": "📋 Include Full Details (southern markets)",
            "type": "boolean",
            "description": "Fetch each product page for ingredients, the on-pack nutrition table, storage instructions and allergen claims. This data exists only on the ALDI SÜD storefronts (UK, Ireland, southern Germany, Austria, Switzerland, Italy, Slovenia, Hungary, Australia) — the ALDI NORD markets do not publish it at all, so turning this on costs nothing extra there and adds nothing. Off is faster and cheaper.",
            "default": true
          },
          "descriptionMaxLength": {
            "title": "✂️ Description Max Length",
            "minimum": 0,
            "type": "integer",
            "description": "Truncate description to N chars. 0 = no truncation.",
            "default": 0
          },
          "compact": {
            "title": "📦 Compact Output",
            "type": "boolean",
            "description": "Core fields only (for AI-agent/MCP workflows).",
            "default": false
          },
          "incrementalMode": {
            "title": "♻️ Incremental Mode",
            "type": "boolean",
            "description": "Compare against previous run state. stateKey is optional — defaults to a signature of search inputs (queries, locations, startUrls, country) so different filter sets never share state.",
            "default": false
          },
          "stateKey": {
            "title": "🔑 State Key",
            "type": "string",
            "description": "Optional. Stable identifier for the tracked search universe. Leave empty to auto-generate from search inputs."
          },
          "skipReposts": {
            "title": "🚫 Skip Reposts",
            "type": "boolean",
            "description": "When incremental, skip listings whose content matches an expired listing from a prior run (cross-run duplicate detection).",
            "default": false
          },
          "telegramToken": {
            "title": "🔑 Telegram Bot Token",
            "type": "string",
            "description": "Telegram bot token (from @BotFather). Required for Telegram notifications."
          },
          "telegramChatId": {
            "title": "💬 Telegram Chat ID",
            "type": "string",
            "description": "Telegram chat or channel ID (e.g. \"-100123456789\"). Required when telegramToken is set."
          },
          "discordWebhookUrl": {
            "title": "🎮 Discord Webhook URL",
            "type": "string",
            "description": "Discord incoming webhook URL. Server Settings → Integrations → Webhooks → New Webhook."
          },
          "slackWebhookUrl": {
            "title": "💼 Slack Webhook URL",
            "type": "string",
            "description": "Slack incoming webhook URL. api.slack.com/messaging/webhooks."
          },
          "notificationLimit": {
            "title": "📊 Max Listings Per Notification",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Maximum number of listings included in each notification message (1–20).",
            "default": 5
          },
          "notifyOnlyChanges": {
            "title": "🔄 Notify Only New/Updated",
            "type": "boolean",
            "description": "When Incremental Mode is on, only send notifications for NEW and UPDATED listings. Has no effect outside incremental mode.",
            "default": false
          },
          "whatsappAccessToken": {
            "title": "📱 WhatsApp Access Token",
            "type": "string",
            "description": "WhatsApp Cloud API permanent access token (System User token from Meta Business). Recipient must have messaged the business number within the last 24h (service-conversation window — free since Nov 2024)."
          },
          "whatsappPhoneNumberId": {
            "title": "📞 WhatsApp Phone Number ID",
            "type": "string",
            "description": "Your WhatsApp Business phone-number ID (numeric, from Meta dashboard). Required when whatsappAccessToken is set."
          },
          "whatsappTo": {
            "title": "📲 WhatsApp Recipient",
            "type": "string",
            "description": "Recipient phone in E.164 format without + (e.g. \"436641234567\"). Recipient must have messaged your business number within last 24h."
          },
          "webhookUrl": {
            "title": "🪝 Generic Webhook URL",
            "type": "string",
            "description": "Receives a JSON POST with {metadata, items} after each run. Universal escape hatch for n8n / Make / Zapier / custom backends."
          },
          "webhookHeaders": {
            "title": "📋 Webhook Headers",
            "type": "object",
            "description": "Optional JSON object of custom headers (e.g. {\"Authorization\":\"Bearer ...\"})."
          },
          "appConnector": {
            "title": "Send results to a connected app",
            "type": "string",
            "description": "Optional. Pick a connected app under Settings → API & Integrations to receive your results (including any contact details). Best-effort across MCP connectors as Apify expands its catalog."
          },
          "mcpIssueTeam": {
            "title": "Issue tracker team",
            "type": "string",
            "description": "Only when the connected app is an issue tracker: the team (name or ID) the summary issue is created under, if that app requires one."
          },
          "descriptionFormat": {
            "title": "Description format",
            "enum": [
              "all",
              "text",
              "html",
              "markdown"
            ],
            "type": "string",
            "description": "Pick a single description representation. `all` keeps every variant; `text` / `html` / `markdown` drop the others.",
            "default": "all"
          },
          "excludeEmptyFields": {
            "title": "Exclude empty fields from output",
            "type": "boolean",
            "description": "Drop null, empty-string, and empty-array fields from each record before push. Smaller payloads for AI agents and dashboards.",
            "default": false
          },
          "emitUnchanged": {
            "title": "🔄 Emit Unchanged Listings",
            "type": "boolean",
            "description": "When incremental mode is on, also emit listings whose content has not changed since the last run.",
            "default": false
          },
          "emitExpired": {
            "title": "⚰️ Emit Expired Listings",
            "type": "boolean",
            "description": "When incremental mode is on, also emit listings that were seen before but are no longer found.",
            "default": false
          }
        }
      },
      "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
                  }
                }
              },
              "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}