{
  "openapi": "3.0.1",
  "info": {
    "title": "immoscout24-kleinanzeigen-apply-bot",
    "description": "Monitors ImmoScout24 and Kleinanzeigen for new rental listings, filters them by area, price per m² and keywords, then sends a personalized application or message from your own account. Includes deduplication, listing snapshots and email alerts.",
    "version": "0.2",
    "x-build-id": "ZaCKV98lL0RVxwuBH"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/beige_quaff~immoscout24-kleinanzeigen-apply-bot/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-beige_quaff-immoscout24-kleinanzeigen-apply-bot",
        "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/beige_quaff~immoscout24-kleinanzeigen-apply-bot/runs": {
      "post": {
        "operationId": "runs-sync-beige_quaff-immoscout24-kleinanzeigen-apply-bot",
        "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/beige_quaff~immoscout24-kleinanzeigen-apply-bot/run-sync": {
      "post": {
        "operationId": "run-sync-beige_quaff-immoscout24-kleinanzeigen-apply-bot",
        "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": [
          "startUrls",
          "applicationTemplate",
          "emailTo"
        ],
        "properties": {
          "platform": {
            "title": "Platform",
            "enum": [
              "immoscout",
              "kleinanzeigen"
            ],
            "type": "string",
            "description": "Which portal this run searches. Run one scheduled task per platform, each with its own queue namespace below.",
            "default": "immoscout"
          },
          "startUrls": {
            "title": "Search URLs",
            "minItems": 1,
            "maxItems": 50,
            "uniqueItems": true,
            "type": "array",
            "description": "Search result URLs from the portal selected above. Set your filters on the website, then copy the URL from the address bar. For Kleinanzeigen prefer one broad city search plus the postal code filter below, because each URL is scraped separately and costs extra proxy traffic.",
            "items": {
              "type": "string",
              "pattern": "^https?:\\/\\/([^\\s\\/$.?#].[^\\s]*)$"
            }
          },
          "monitorMode": {
            "title": "Only new listings",
            "type": "boolean",
            "description": "Recommended. Returns only listings that appeared since the previous run, which keeps scheduled runs cheap. The very first run just records a baseline and returns nothing.",
            "default": true
          },
          "pageLimit": {
            "title": "Page limit (ImmoScout24 only)",
            "type": "integer",
            "description": "How many result pages the ImmoScout24 scraper reads. 0 means no explicit limit. Ignored for Kleinanzeigen.",
            "default": 0
          },
          "kaMaxResults": {
            "title": "Max results (Kleinanzeigen only)",
            "minimum": 0,
            "type": "integer",
            "description": "Caps how many listings the Kleinanzeigen scraper returns per search. 0 means unlimited. Ignored for ImmoScout24.",
            "default": 0
          },
          "kvNamespace": {
            "title": "Queue namespace",
            "type": "string",
            "description": "Keeps the listing queue of this task separate from your other tasks. Use a unique value per search, for example is_berlin or ka_berlin. Change it to start over with an empty queue."
          },
          "searchProfileId": {
            "title": "Search profile ID",
            "type": "string",
            "description": "Alternative way to scope the queue namespace when the field above is left empty."
          },
          "scraperActorId": {
            "title": "ImmoScout24 scraper Actor override",
            "type": "string",
            "description": "Advanced. Replaces the default scraper clearpath/immoscout24-api-pro. The replacement must return the same fields."
          },
          "applyActorId": {
            "title": "ImmoScout24 apply Actor override",
            "type": "string",
            "description": "Advanced. Replaces the default apply Actor clearpath/immoscout24-apply-bot."
          },
          "kaScraperActorId": {
            "title": "Kleinanzeigen scraper Actor override",
            "type": "string",
            "description": "Advanced. Replaces the default scraper clearpath/kleinanzeigen-immobilien-api-pro."
          },
          "kaMessageActorId": {
            "title": "Kleinanzeigen message Actor override",
            "type": "string",
            "description": "Advanced. Replaces the default message Actor clearpath/kleinanzeigen-message-api."
          },
          "username": {
            "title": "ImmoScout24 email",
            "type": "string",
            "description": "The email address of your own ImmoScout24 account. Required when searching ImmoScout24 with applications enabled."
          },
          "password": {
            "title": "ImmoScout24 password",
            "type": "string",
            "description": "Only needed when the apply Actor has no stored session yet. Stored encrypted."
          },
          "useStoredCredentials": {
            "title": "Reuse stored ImmoScout24 session",
            "type": "boolean",
            "description": "Recommended. Lets the apply Actor reuse the session it already stored instead of logging in on every run.",
            "default": true
          },
          "kaEmail": {
            "title": "Kleinanzeigen email",
            "type": "string",
            "description": "The email address of your own Kleinanzeigen account. Required when searching Kleinanzeigen with messaging enabled. Log the account in once beforehand, see the README."
          },
          "kaPassword": {
            "title": "Kleinanzeigen password",
            "type": "string",
            "description": "Only needed for the one-time login of the Kleinanzeigen message Actor. Normal runs do not use it. Stored encrypted."
          },
          "applicationTemplate": {
            "title": "Application text",
            "type": "string",
            "description": "The message sent to the landlord. Placeholders are filled per listing: {{anrede}} salutation, {{roomsStr}} rooms, {{sizeStr}} size in m2, {{altbauSuffix}} adds ' Altbau' for pre-1950 buildings, {{locationSuffix}} district and street, {{highlightsSuffix}} condition and balcony sentence, {{vacantPhrase}} move-in date sentence, {{abloeseSentence}} added when the listing mentions a handover fee, {{aiParagraph}} optional AI sentence. Wrap a sentence in (pictures)...(/pictures) to include it only when the listing has photos. Aliases: (photos), (fotos), (bilder)."
          },
          "openaiEnabled": {
            "title": "AI personalization enabled",
            "type": "boolean",
            "description": "If enabled, OpenAI can generate a short personalized paragraph based on listing text (description, furnishing_description, location_description). Note: AI generation runs only when your applicationTemplate contains {{aiParagraph}}.",
            "default": false
          },
          "openaiApiKey": {
            "title": "OpenAI API key",
            "type": "string",
            "description": "OpenAI API key used for AI personalization. Stored as a secret in Apify."
          },
          "openaiModel": {
            "title": "OpenAI model",
            "type": "string",
            "description": "Model to use for AI personalization (e.g. gpt-4o-mini).",
            "default": "gpt-4o-mini"
          },
          "openaiTemperature": {
            "title": "AI temperature",
            "minimum": 0,
            "maximum": 2,
            "type": "number",
            "description": "Higher = more creative, lower = more deterministic.",
            "default": 0.3
          },
          "openaiMaxTokens": {
            "title": "AI max tokens",
            "minimum": 50,
            "maximum": 2000,
            "type": "integer",
            "description": "Token cap for the AI response.",
            "default": 160
          },
          "openaiMaxChars": {
            "title": "AI max chars per listing field",
            "minimum": 120,
            "maximum": 2000,
            "type": "integer",
            "description": "Per-field character cap before sending listing text to AI (applies to description, furnishing_description, and location_description).",
            "default": 1800
          },
          "openaiMinListingChars": {
            "title": "Min listing text length",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Only call AI if combined listing text length is at least this many characters.",
            "default": 80
          },
          "openaiMaxListingChars": {
            "title": "Max listing text length",
            "minimum": 200,
            "maximum": 20000,
            "type": "integer",
            "description": "Combined character cap for listing text sent to AI after per-field truncation.",
            "default": 3000
          },
          "openaiDebug": {
            "title": "Debug AI output",
            "type": "boolean",
            "description": "If enabled, logs the AI prompt/response summary to the console.",
            "default": false
          },
          "maxAppliesPerRun": {
            "title": "Max applications per run",
            "minimum": 1,
            "type": "integer",
            "description": "Upper limit of applications sent in a single run. Each sent application is billed, so keep this low while testing. Remaining listings stay queued for the next run.",
            "default": 1
          },
          "excludedListingKeywords": {
            "title": "Exclude listings containing",
            "maxItems": 100,
            "type": "array",
            "description": "Listings whose text contains any of these words are skipped. Matching ignores case and simple plural forms, and covers title, description, furnishing, location and contact fields.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "excludedListingKeywordsText": {
            "title": "Exclude listings containing (text fallback)",
            "type": "string",
            "description": "Use this if the list field above does not save your entries. One keyword per line, or separated by commas or semicolons."
          },
          "debugListingKeywordFilter": {
            "title": "Log keyword filter decisions",
            "type": "boolean",
            "description": "Logs why each listing matched or missed a keyword. Useful when a filter behaves unexpectedly.",
            "default": false
          },
          "maxColdPricePerSqm": {
            "title": "Max cold rent per m2 (EUR)",
            "minimum": 0,
            "type": "number",
            "description": "Skips listings above this cold rent per square metre. Cold rent excludes ancillary and heating costs."
          },
          "maxWarmPricePerSqm": {
            "title": "Max total rent per m2 (EUR)",
            "minimum": 0,
            "type": "number",
            "description": "Skips listings above this total rent per square metre, including ancillary and heating costs."
          },
          "skipExposesByPricePerSqm": {
            "title": "Enable rent per m2 filtering",
            "type": "boolean",
            "description": "Turn off to ignore both rent per m2 limits above without clearing them.",
            "default": true
          },
          "allowedZipCodes": {
            "title": "Postal codes to search around (Berlin only)",
            "maxItems": 100,
            "type": "array",
            "description": "List the Berlin postal codes you want to live near. Neighbouring postal codes, map coordinates and district names are derived automatically using the radius below, so one broad city search can replace one search URL per postal code. Leave empty to keep every listing the search returns. Currently only Berlin postal codes are supported.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "allowedZipCodesText": {
            "title": "Postal codes (text fallback)",
            "type": "string",
            "description": "Use this if the list field above does not save your entries. One postal code per line, or separated by commas, semicolons or spaces."
          },
          "locationRadiusKm": {
            "title": "Radius around each postal code (km)",
            "minimum": 0.1,
            "maximum": 50,
            "type": "number",
            "description": "How far from each postal code centre a listing may be. Also decides which neighbouring postal codes count as in range. 1.5 works well because the portals report approximate coordinates.",
            "default": 1.5
          },
          "allowedDistricts": {
            "title": "Allowed districts (optional override)",
            "maxItems": 100,
            "type": "array",
            "description": "Only used for listings that have neither coordinates nor a postal code. Leave empty to use the districts derived from your postal codes, which is recommended.",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "allowedDistrictsText": {
            "title": "Allowed districts (text fallback)",
            "type": "string",
            "description": "Use this if the list field above does not save your entries. One district per line, or separated by commas or semicolons."
          },
          "skipListingsWithUnknownLocation": {
            "title": "Skip listings without any location data",
            "type": "boolean",
            "description": "Off by default so nothing is lost. Listings with no coordinates, postal code or district are kept and counted as unresolved in the run summary. Only turn this on once you have confirmed that count stays near zero.",
            "default": false
          },
          "debugLocationFilter": {
            "title": "Log area filter decisions",
            "type": "boolean",
            "description": "Logs which signal decided each listing and how far it was from your postal codes. Useful for a first dry run.",
            "default": false
          },
          "delaySecondsBetweenApplies": {
            "title": "Delay between applications (seconds)",
            "minimum": 0,
            "type": "integer",
            "description": "Pause between two applications in the same run, to look less automated to the portal.",
            "default": 30
          },
          "runApply": {
            "title": "Send applications",
            "type": "boolean",
            "description": "Off by default. While off, the Actor only collects and filters listings so you can verify the results first. Turn it on to actually send applications from your account.",
            "default": false
          },
          "sendEmail": {
            "title": "Send email notification",
            "type": "boolean",
            "description": "Emails you a summary with photos and the sent text after each successful application.",
            "default": true
          },
          "emailTo": {
            "title": "Your email address",
            "type": "string",
            "description": "Where notifications are sent. Use an inbox you actually monitor."
          },
          "mailTimeoutMs": {
            "title": "Email timeout (ms)",
            "type": "integer",
            "description": "How long to wait for the email Actor before giving up on a notification.",
            "default": 60000
          },
          "storeSnapshots": {
            "title": "Save listing snapshots",
            "type": "boolean",
            "description": "Saves each listing you applied to as a self-contained HTML page plus the raw data, so you still have it after the ad is taken down.",
            "default": true
          },
          "storeMedia": {
            "title": "Include photos and documents",
            "type": "boolean",
            "description": "Downloads listing photos and PDF documents into the snapshot. Turn off to reduce storage and transfer costs.",
            "default": true
          },
          "maxPhotosToStore": {
            "title": "Max photos per listing",
            "minimum": 0,
            "type": "integer",
            "description": "How many photos to save per listing. Documents are not limited by this.",
            "default": 10
          },
          "photoResolutionMode": {
            "title": "Photo quality",
            "enum": [
              "web_first",
              "full_first",
              "hybrid"
            ],
            "type": "string",
            "description": "Full resolution looks best but costs the most transfer. Hybrid saves the first few photos at full resolution and the rest at web resolution.",
            "default": "hybrid"
          },
          "fullResPhotoCount": {
            "title": "Full resolution photos in hybrid mode",
            "minimum": 0,
            "maximum": 50,
            "type": "integer",
            "description": "How many of the first photos are saved at full resolution when photo quality is set to hybrid.",
            "default": 2
          },
          "maxBytesTotal": {
            "title": "Max total media size per listing (bytes)",
            "type": "integer",
            "description": "Media downloads for a listing stop once this total is exceeded.",
            "default": 30000000
          },
          "perFileMaxBytes": {
            "title": "Max size per file (bytes)",
            "type": "integer",
            "description": "Individual photos or documents larger than this are skipped.",
            "default": 8000000
          },
          "downloadTimeoutMs": {
            "title": "Download timeout per file (ms)",
            "type": "integer",
            "description": "How long to wait for a single photo or document before skipping it.",
            "default": 15000
          },
          "opsLogEnabled": {
            "title": "Enable persistent ops dashboard",
            "type": "boolean",
            "description": "If enabled, writes a cross-run JSON log and filterable HTML dashboard to the persistent STATE key-value store.",
            "default": true
          },
          "opsLogMaxEvents": {
            "title": "Max ops dashboard events",
            "minimum": 100,
            "maximum": 10000,
            "type": "integer",
            "description": "Maximum number of recent detail events retained in the persistent ops JSON log and dashboard. Run history is controlled separately.",
            "default": 1000
          },
          "opsLogMaxRuns": {
            "title": "Max ops dashboard runs",
            "minimum": 50,
            "maximum": 250000,
            "type": "integer",
            "description": "Maximum number of compact run summaries retained in the persistent ops JSON log and dashboard. The whole log is rewritten on every flush, so higher values increase key-value writes and data transfer costs.",
            "default": 500
          },
          "opsLogMaxFilteredListings": {
            "title": "Max filtered listing records",
            "minimum": 50,
            "maximum": 500000,
            "type": "integer",
            "description": "Maximum number of compact filtered-listing records retained in the persistent ops JSON log and dashboard. Higher values increase key-value writes and data transfer costs.",
            "default": 2000
          },
          "opsLogMaxApplications": {
            "title": "Max application records",
            "minimum": 50,
            "maximum": 500000,
            "type": "integer",
            "description": "Maximum number of compact application attempt/result records retained in the persistent ops JSON log and dashboard. Higher values increase key-value writes and data transfer costs.",
            "default": 2000
          },
          "enqueueLimitPerRun": {
            "title": "Max listings queued per run",
            "minimum": 1,
            "type": "integer",
            "description": "Caps how many new listings enter the queue in one run. Leave empty for no limit."
          },
          "debugEmailOnly": {
            "title": "Preview application texts only",
            "type": "boolean",
            "description": "Renders the application text for a few listings into the log and sends nothing. Useful for checking your template.",
            "default": false
          },
          "debugQueueCount": {
            "title": "How many texts to preview",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "Number of application texts rendered when the preview option above is enabled.",
            "default": 1
          },
          "debugPickIndex": {
            "title": "Start preview at listing number",
            "minimum": 0,
            "type": "integer",
            "description": "Which listing from the search results the preview starts at.",
            "default": 0
          },
          "debugNoQueueWrites": {
            "title": "Do not save anything to the queue",
            "type": "boolean",
            "description": "Runs without touching the stored queue, so you can try a new search without affecting a running task.",
            "default": false
          },
          "debugApplicationMessage": {
            "title": "Preview fallback text",
            "type": "string",
            "description": "Used in preview mode when no application text is set.",
            "default": "(preview mode - no application was sent)"
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Proxy used by the ImmoScout24 scraper. Apify Proxy is recommended. The Kleinanzeigen scraper manages its own proxy.",
            "default": {
              "useApifyProxy": true
            }
          },
          "useApifyProxy": {
            "title": "Use Apify Proxy for applications",
            "type": "boolean",
            "description": "Routes the ImmoScout24 apply Actor through Apify Proxy.",
            "default": true
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}