{
  "openapi": "3.0.1",
  "info": {
    "title": "Willhaben Property Scraper - Austria Real Estate Data",
    "description": "Scrape every willhaben.at property listing across Austria — apartments, houses, plots and commercial, to buy or to rent. Price, price per m², area, rooms, GPS, agency and photos on every row, plus the energy certificate and agency phone number on demand.",
    "version": "1.0",
    "x-build-id": "UEDBQhsa1YcOqBFhd"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/sian.agency~willhaben-property-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-sian.agency-willhaben-property-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/sian.agency~willhaben-property-scraper/runs": {
      "post": {
        "operationId": "runs-sync-sian.agency-willhaben-property-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/sian.agency~willhaben-property-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-sian.agency-willhaben-property-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": {
          "operation": {
            "title": "🎯 What do you want to scrape?",
            "enum": [
              "search",
              "detail"
            ],
            "type": "string",
            "description": "🎯 **PICK ONE PER RUN.**\n\n🔍 **Property Listing** — every listing in a willhaben property category that matches your filters. This is the one you want 95% of the time.\n\n📄 **Property Detail** — you already have listing links or ad IDs and want the full description, the energy certificate and the agency's phone number for each.\n\n💡 Want the details on a LISTING run instead? Leave this on Property Listing and switch on **Add full details** below.",
            "default": "search"
          },
          "propertyCategory": {
            "title": "🏘️ Property category",
            "enum": [
              "101",
              "131",
              "102",
              "132",
              "14",
              "15",
              "16",
              "42",
              "12",
              "32",
              "35",
              "90"
            ],
            "type": "string",
            "description": "🏘️ **WHICH SECTION OF WILLHABEN** to sweep. All twelve property categories are here, exactly as willhaben splits them.\n\n🏢 **Apartments for sale** is the biggest single category in Austria — roughly 42,000 live listings.\n\n🗂️ **All property in one sweep** returns every section together when you want the whole market rather than one slice.\n\n💡 Sale and rental prices live in the same Price column, so pick one category per run and merge afterwards.",
            "default": "101"
          },
          "province": {
            "title": "📍 Province (Bundesland)",
            "enum": [
              "all",
              "900",
              "3",
              "4",
              "6",
              "7",
              "5",
              "2",
              "8",
              "1",
              "22000"
            ],
            "type": "string",
            "description": "📍 **WHICH PART OF AUSTRIA.** Leave it on All of Austria for a national dataset.\n\n🏙️ **Wien** alone carries about half the country's apartment listings, so it is usually worth its own run.\n\n🎯 Splitting a big category province by province is also the tidiest way to run several short scheduled jobs instead of one long one.\n\n🌍 **Other countries** is willhaben's own bucket for cross-border listings advertised to Austrian buyers.",
            "default": "all"
          },
          "keyword": {
            "title": "🔑 Keyword",
            "type": "string",
            "description": "🔑 **WHAT TO LOOK FOR** — the same words you would type into willhaben's own search box. It matches the headline and the listing body, so `Altbau` also finds \"charmante Altbauwohnung\".\n\n⬜ **Leave it empty to take the whole category.** That is the fastest way to build a full market dataset.\n\n🇦🇹 Listings are written in German, so German words match far more than English ones.\n\n💡 One keyword per run. To sweep several, schedule one run per keyword — each is billed only for the rows it returns.",
            "default": ""
          },
          "maxResults": {
            "title": "🔢 Max listings",
            "minimum": 1,
            "maximum": 50000,
            "type": "integer",
            "description": "🔢 **STOP AFTER THIS MANY LISTINGS**, counted across the whole run.\n\n📦 Listings arrive 200 at a time, so the run finishes the page it is on and then stops — you may receive a few more than you asked for, and you are only charged for rows delivered.\n\n💰 **Free accounts are capped at 25 rows per run** whatever you type here. Paid accounts are not.\n\n🚀 There is no depth ceiling on willhaben, so a whole 42,000-listing category really does come out in one run.",
            "default": 100
          },
          "includeDetails": {
            "title": "📄 Add full details (extra charge)",
            "type": "boolean",
            "description": "📄 **OPENS EVERY LISTING PAGE AND READS IT.** Adds the full description, the energy certificate (HWB value and class), heating and building type, running costs, the availability date and the agency's phone number and website.\n\n💰 **Charged per enriched listing** on top of the listing row. Leave it off and you pay listing rows only.\n\n🎯 **Worth it for:** lead generation, renovation targeting and yield work.\n❌ **Skip it for:** price tracking. The results card already carries price and area.",
            "default": false
          },
          "listingUrls": {
            "title": "🔗 Listing URLs or ad IDs",
            "uniqueItems": true,
            "type": "array",
            "description": "🔗 **FOR PROPERTY DETAIL MODE:** the willhaben listings you want expanded.\n\n📱 Open the listing → copy the address bar. Both forms work: the full `…-1738704240/` address and the `willhaben.at/iad/object?adId=1738704240` short link. Have only the ad id? Wrap it in that short link — a bare number is rejected before the run starts.\n\n📝 **Bulk edit** — one per line. 📁 **Upload a .txt file**. 🔗 **+ Add** — one at a time.\n\n🕒 willhaben removes a listing once it sells, so an old id may not resolve.",
            "default": [],
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "searchUrls": {
            "title": "🌐 Search URLs",
            "uniqueItems": true,
            "type": "array",
            "description": "🌐 **PASTE A WILLHABEN SEARCH INSTEAD OF FILLING THE FORM.** Set the filters on willhaben.at, copy the address bar, drop it here.\n\n🎛️ **Every filter in that URL is honoured** — including ones the form does not expose, such as a single Viennese district, building type or a specific fitting.\n\n⚠️ **A pasted search REPLACES the form:** with anything here, the category, province and filters above are ignored for the run.",
            "default": [],
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "minPrice": {
            "title": "💵 Min price (€)",
            "minimum": 0,
            "type": "integer",
            "description": "💵 **CHEAPEST LISTING TO INCLUDE**, in euro.\n\n⬜ **0 means no lower bound** — that is the default.\n\n🔑 On rental categories this is the monthly rent, not a purchase price, so €500 means €500 a month.\n\n🎯 Filtering happens at willhaben, so a price band makes the run faster and cheaper: you are not billed for rows you filtered out.",
            "default": 0
          },
          "maxPrice": {
            "title": "💰 Max price (€)",
            "minimum": 0,
            "type": "integer",
            "description": "💰 **MOST EXPENSIVE LISTING TO INCLUDE**, in euro.\n\n⬜ **0 means no upper bound** — that is the default.\n\n🎯 Pair it with Min price to walk a big category one band at a time, which is also how you keep each scheduled run short: €0-200k, then €200-400k, and so on.",
            "default": 0
          },
          "minLivingArea": {
            "title": "📐 Min living area (m²)",
            "minimum": 0,
            "type": "integer",
            "description": "📐 **SMALLEST LIVING AREA TO INCLUDE**, in square metres.\n\n⬜ **0 means no lower bound** — that is the default.\n\n🌳 Plots are measured by plot area rather than living area, so this filter does nothing on the land category.",
            "default": 0
          },
          "maxLivingArea": {
            "title": "📏 Max living area (m²)",
            "minimum": 0,
            "type": "integer",
            "description": "📏 **LARGEST LIVING AREA TO INCLUDE**, in square metres.\n\n⬜ **0 means no upper bound** — that is the default.\n\n🎯 Useful with Min living area to isolate one product type: 60-79 m² is the classic Austrian two-room flat.",
            "default": 0
          },
          "rooms": {
            "title": "🛏️ Rooms",
            "enum": [
              "any",
              "1X1",
              "2X2",
              "3X3",
              "4X4",
              "5X5",
              "6X9",
              "10X"
            ],
            "type": "string",
            "description": "🛏️ **EXACT ROOM COUNT**, as willhaben counts it.\n\n⚠️ **An Austrian room count includes the living room**, so a two-room flat is a one-bedroom flat. Do not translate it straight into bedrooms.\n\n🌳 Categories without rooms, such as plots, ignore this.\n\n💡 To take a spread, run one number per run rather than guessing a range.",
            "default": "any"
          },
          "outdoorSpace": {
            "title": "🌿 Outdoor space",
            "enum": [
              "any",
              "20",
              "10",
              "60",
              "30",
              "40",
              "50"
            ],
            "type": "string",
            "description": "🌿 **ONLY LISTINGS THAT ADVERTISE THIS KIND OF OUTDOOR SPACE.**\n\n🪟 Roughly two in five Austrian apartments carry a balcony, so this is a meaningful cut rather than a rare one.\n\n🏛️ A **loggia** is a recessed balcony inside the building line — common in Viennese new builds and priced differently from a balcony.\n\n💡 Leave it on Any to count the whole market.",
            "default": "any"
          },
          "availableNow": {
            "title": "🚚 Available immediately",
            "type": "boolean",
            "description": "🚚 **ONLY LISTINGS THE SELLER MARKS AS AVAILABLE RIGHT AWAY.**\n\n🔑 Most useful on rentals, where a flat free in six months is noise if you are moving next month.\n\n📆 The exact handover date lands in the Available from column when full details are on.",
            "default": false
          },
          "postedLast48Hours": {
            "title": "🆕 Posted in the last 48 hours",
            "type": "boolean",
            "description": "🆕 **ONLY WHAT WENT UP IN THE LAST TWO DAYS.**\n\n⏰ **This is the scheduling switch.** Run the actor daily with this on and you pay for the new listings only, instead of re-buying the whole market every morning.\n\n🎯 First-mover advantage on rentals in Wien, where a well-priced flat is gone within hours.\n\n💡 Pair it with Sort by newest first.",
            "default": false
          },
          "sort": {
            "title": "↕️ Sort by",
            "enum": [
              "1",
              "3",
              "4",
              "5",
              "6",
              "7"
            ],
            "type": "string",
            "description": "↕️ **WHICH LISTINGS COME FIRST** — and, when Max listings caps the run, which sample you actually keep.\n\n🕒 **Newest first** for monitoring and lead generation.\n⬆️ **Cheapest first** for bargain hunting.\n🎯 **Most relevant** when you have typed a keyword.\n\n💡 Sorting is willhaben's own, applied before anything is billed.",
            "default": "1"
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}