{
  "openapi": "3.0.1",
  "info": {
    "title": "DDproperty Thailand Scraper - Properties, Prices & Agents",
    "description": "Scrape DDproperty.com Thailand listings at scale. Extract prices, property features, images, agent contacts, GPS coordinates, nearby BTS/MRT transit and more. Built for Thai real estate analytics, market research and investment analysis.",
    "version": "2.0",
    "x-build-id": "1Dmu82V1KYYJOrpOF"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~ddproperty-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-ddproperty-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~ddproperty-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-ddproperty-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~ddproperty-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-ddproperty-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": {
          "mode": {
            "title": "1. Search mode",
            "enum": [
              "search",
              "url"
            ],
            "type": "string",
            "description": "Search mode = build URLs from the filters below. URL mode = paste one or more ddproperty.com search URLs (recommended for refined searches; pagination still auto-advances forward from any ?page=N you provide).",
            "default": "search"
          },
          "listing_type": {
            "title": "Listing type (Search mode)",
            "enum": [
              "sale",
              "rent"
            ],
            "type": "string",
            "description": "sale or rent",
            "default": "sale"
          },
          "property_type": {
            "title": "Property type (Search mode)",
            "enum": [
              "CONDO",
              "BUNG",
              "SEMI",
              "VIL",
              "TOWN",
              "LAND",
              "APT",
              "RET",
              "OFF",
              "WAR",
              "BIZ",
              "SHOP"
            ],
            "type": "string",
            "description": "Filter by property type code"
          },
          "search": {
            "title": "Location search (Search mode)",
            "type": "string",
            "description": "Free-text location search (e.g. 'Sukhumvit', 'Ari', 'Phuket'). Use this OR the region code below, not both. If both are set, this takes priority."
          },
          "region": {
            "title": "Region / district / area code (Search mode)",
            "type": "string",
            "description": "Location code: region (TH10=Bangkok, TH83=Phuket), district (TH1033=Watthana), or area (TH103302=Khlong Tan)."
          },
          "min_price": {
            "title": "Min price (THB) (Search mode)",
            "type": "integer",
            "description": "Minimum price in Thai Baht"
          },
          "max_price": {
            "title": "Max price (THB) (Search mode)",
            "type": "integer",
            "description": "Maximum price in Thai Baht"
          },
          "bedrooms": {
            "title": "Bedrooms (Search mode)",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Number of bedrooms (0=Studio)"
          },
          "sort": {
            "title": "Sort by (Search mode)",
            "enum": [
              "date",
              "price",
              "psf"
            ],
            "type": "string",
            "description": "Sort results",
            "default": "date"
          },
          "sort_order": {
            "title": "Sort order (Search mode)",
            "enum": [
              "asc",
              "desc"
            ],
            "type": "string",
            "description": "Sort direction: ascending or descending",
            "default": "desc"
          },
          "urls": {
            "title": "Search URLs (URL mode)",
            "type": "array",
            "description": "One or more ddproperty.com links. Open the site in a browser, refine your search with any filters, then paste the resulting URLs here. Listing-page links (region, district, near-station, property-type, commercial, filtered/sorted, new-launch) are walked page by page: pagination auto-advances forward from each URL, and a ?page=N start page is honoured. Single-page links: a listing detail page, a project detail page (with its unit-type price ladder) and an agent profile page return one record each; the agent directory page returns one agent row per featured card (about 30 to 35, a rotating set) and the agent search page up to 20 agent rows. Every row counts against Max properties and is billed. In URL mode, the search-mode fields above are ignored. Bare ddproperty.com links are normalised to www. The /th/ locale is refused by the site and rejected up front. The prefilled list has one example link per shape, but all links share the Max properties budget (default 20), so the first link fills it; raise Max properties or remove links to reach the other shapes.",
            "items": {
              "type": "string"
            },
            "default": [
              "https://www.ddproperty.com/en/property-for-sale/in-bangkok-th10",
              "https://www.ddproperty.com/en/property-for-rent/in-bangkok-th10",
              "https://www.ddproperty.com/en/property-for-sale",
              "https://www.ddproperty.com/en/property-for-sale/in-bangkok-th10?page=2",
              "https://www.ddproperty.com/en/property-for-sale?freetext=sukhumvit&propertyTypeCode=CONDO&minprice=2000000&bedrooms=2&sort=price&order=asc",
              "https://www.ddproperty.com/en/property-for-sale/in-bangkok-th10/priced-under-1m-thb",
              "https://www.ddproperty.com/en/property-for-sale/in-bang-bon-th1050",
              "https://www.ddproperty.com/en/property-for-sale/near-e9-on-nut-bts-2174",
              "https://www.ddproperty.com/en/condo-for-sale",
              "https://www.ddproperty.com/en/detached-house-for-sale",
              "https://www.ddproperty.com/en/commercial-property-for-sale",
              "https://www.ddproperty.com/en/new-property-launch?listingType=sale&page=1",
              "https://www.ddproperty.com/en/property/ideo-mobi-rama-9-bangkok-for-sale-500188725",
              "https://www.ddproperty.com/en/property/project/chapter-one-spark-charan-bangkok-for-sale-500444048",
              "https://www.ddproperty.com/en/agent/aksarapak-chittara-1265048",
              "https://www.ddproperty.com/en/agent-directory",
              "https://www.ddproperty.com/en/condo-for-sale/in-bangkok-th10",
              "https://www.ddproperty.com/en/condo-for-sale?freetext=Sukhumvit",
              "https://www.ddproperty.com/en/property-for-sale?freetext=Sukhumvit",
              "https://www.ddproperty.com/en/new-property-launch?region_code=TH10"
            ]
          },
          "startUrls": {
            "title": "Start URLs (same as Search URLs)",
            "type": "array",
            "description": "ddproperty.com search URLs. Same as \"Search URLs (URL mode)\"; setting this switches the run to URL mode. Plain strings or {\"url\": ...} objects are accepted.",
            "items": {
              "type": "string"
            }
          },
          "searchQueries": {
            "title": "Search queries (one search per entry)",
            "type": "array",
            "description": "Free-text location queries such as \"Sukhumvit\" or \"Phuket\". Each entry runs as its own search with the filters above; Max items / Max properties is the TOTAL cap across all queries.",
            "items": {
              "type": "string"
            }
          },
          "country": {
            "title": "Country",
            "enum": [
              "th",
              "sg",
              "my",
              "vn"
            ],
            "type": "string",
            "description": "Only \"th\" (Thailand) is served by this actor. sg, my and vn are accepted for compatibility but the run stops with a pointer to the sister scrapers.",
            "default": "th"
          },
          "listingType": {
            "title": "Listing type (alias of listing_type)",
            "enum": [
              "sale",
              "rent"
            ],
            "type": "string",
            "description": "sale or rent. Same value as \"Listing type (Search mode)\"."
          },
          "propertyType": {
            "title": "Property type (alias of property_type)",
            "enum": [
              "auto",
              "th_all",
              "th_condo",
              "th_single_detached",
              "th_semi_detached",
              "th_villa",
              "th_townhouse",
              "th_land",
              "th_apartment",
              "sg_all",
              "sg_condo",
              "sg_landed",
              "sg_hdb",
              "my_all",
              "my_bungalow",
              "my_apartment",
              "my_semi_detached",
              "my_terrace",
              "my_land",
              "vn_all",
              "vn_apartment",
              "vn_mini_apartment",
              "vn_house",
              "vn_land",
              "vn_farm_resort",
              "vn_warehouse_factory",
              "vn_other"
            ],
            "type": "string",
            "description": "th_* values map to the property_type codes: th_condo=CONDO, th_single_detached=BUNG, th_semi_detached=SEMI, th_villa=VIL, th_townhouse=TOWN, th_land=LAND, th_apartment=APT. auto and th_all apply no type filter. sg_*, my_* and vn_* values are out of scope and stop the run."
          },
          "minPrice": {
            "title": "Min price, THB (alias of min_price)",
            "type": "integer",
            "description": "Same value as \"Min price (THB)\"."
          },
          "maxPrice": {
            "title": "Max price, THB (alias of max_price)",
            "type": "integer",
            "description": "Same value as \"Max price (THB)\"."
          },
          "maxItems": {
            "title": "Max items (alias of max_properties)",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Same value as \"Max properties\" (0 = unlimited). Total cap across all URLs and queries."
          },
          "max_properties": {
            "title": "Max properties",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Maximum number of properties to scrape (0=unlimited). Caps both Search and URL modes. Pagination stops automatically when this cap is hit or the site runs out of results. Hard upper bound 100000.",
            "default": 20
          },
          "enable_detail_pages": {
            "title": "Fetch detail pages",
            "type": "boolean",
            "description": "Fetch the per-listing detail page in addition to the search page. Adds latitude/longitude, description, facilities, project info, etc.",
            "default": true
          },
          "detail_concurrency": {
            "title": "Detail page concurrency",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "Parallel detail-page fetches. All concurrent requests share one proxy IP, so values above 3 risk per-IP rate limiting.",
            "default": 3
          },
          "session_ttl_seconds": {
            "title": "Session TTL (seconds)",
            "minimum": 60,
            "maximum": 1800,
            "type": "integer",
            "description": "How long to reuse a single edge session before forcing a refresh.",
            "default": 300
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Residential proxy with country=TH is the default and recommended. The session is bound to a single proxy IP and is reused across requests internally."
          },
          "resumeFromRunId": {
            "title": "Resume from run/dataset ID",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue that ONE interrupted crawl - properties it already collected are skipped, not re-scraped. Unrelated to Incremental mode below, which tracks a recurring search across scheduled runs."
          },
          "incrementalMode": {
            "title": "Incremental mode (recurring monitoring)",
            "type": "boolean",
            "description": "When ON, this actor remembers the last run of this SAME search (via its own saved state, keyed on your filters or on State key below) and classifies every property as NEW / UPDATED / REAPPEARED / EXPIRED. Unrelated to Resume from run/dataset ID above, which continues one specific interrupted run. Default OFF - normal runs return every matching property every time.",
            "default": false
          },
          "stateKey": {
            "title": "State key (Incremental mode only)",
            "type": "string",
            "description": "Optional. Set this to a name of your choice to manually control which runs share incremental state (e.g. to deliberately merge two different searches into one monitoring campaign). Leave blank to auto-derive the key from your search filters - two different filter setups then never share a baseline."
          },
          "emitUnchanged": {
            "title": "Emit unchanged properties (Incremental mode only)",
            "type": "boolean",
            "description": "When ON, properties with no detected change are still returned (tagged changeType=UNCHANGED) instead of being suppressed. Off by default so a recurring run returns only what actually changed. Turning this ON returns - and bills, at the standard per-result rate - every property scanned, not just the changed ones.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired properties (Incremental mode only)",
            "type": "boolean",
            "description": "When ON, properties tracked by a previous incremental run that no longer appear are returned once, tagged changeType=EXPIRED. Only fires after a run that scans its search to a genuine natural end (no Max properties cap hit, no Resume) - a partial run leaves previous state untouched instead of guessing. Turning this ON returns - and bills, at the standard per-result rate - these extra rows.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Incremental mode only. Field names (e.g. price_formatted, badges) that must NOT count as a change: they stay in the output but never make a listing UPDATED or appear in changedFields. Matches the name at any depth. Already ignored automatically: recency, a relative posted_date text (\"2 days ago\"), and query strings on image URLs. Leave empty to detect changes on every other field.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com)."
          },
          "notionParentPageUrl": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on items written to each connector per run. Does not affect the dataset.",
            "default": 50
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}