{
  "openapi": "3.0.1",
  "info": {
    "title": "Batdongsan.com.vn - Property Listings, Prices & Agents",
    "description": "From $1/1K. Scrape Batdongsan.com.vn property listings into clean JSON. Search by listing type, property category, city, or search URL. Automatically paginate results and extract prices, GPS coordinates, property specs, agent details, listing dates, and high-resolution photos.",
    "version": "1.1",
    "x-build-id": "zTeVrmeYFh93Q00NT"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~batdongsan-com-vn-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-batdongsan-com-vn-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~batdongsan-com-vn-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-batdongsan-com-vn-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~batdongsan-com-vn-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-batdongsan-com-vn-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 = pick listing type (buy/rent) + property type + city below, plus optional price/area/bedroom/direction/keyword filters and a sort order. URL mode = paste any batdongsan.com.vn URL already refined in a browser (a search page, a project page or a single listing).",
            "default": "search"
          },
          "listingType": {
            "title": "Buy or rent? (Search mode)",
            "enum": [
              "Buy",
              "Rent",
              "BuyAndRent"
            ],
            "type": "string",
            "description": "Bán (Buy), Cho thuê (Rent), or both in one run (one Buy and one Rent search per city; each record is labelled with its own Buy/Rent). Search mode only.",
            "default": "Buy"
          },
          "propertyType": {
            "title": "Property type (Search mode)",
            "enum": [
              "All",
              "Apartment",
              "MiniApartment",
              "PrivateHouse",
              "TownHouse",
              "Villa",
              "Shophouse",
              "Land",
              "ProjectLand",
              "Condotel",
              "FarmResort",
              "Office",
              "Warehouse",
              "Room",
              "ShopKiosk",
              "Other"
            ],
            "type": "string",
            "description": "What kind of property to search for. Maps to a batdongsan.com.vn category. Search mode only. Some categories exist in only one direction on batdongsan: Land, Project land, Condotel and Farm/resort are buy-only; Office, Room for rent and Shop/kiosk are rent-only. Picking a direction the site doesn't have fails the run with a clear message (with \"Buy and rent\", the missing side is skipped).",
            "default": "Apartment"
          },
          "locations": {
            "title": "Cities / provinces to search (Search mode)",
            "type": "array",
            "description": "One or more of Vietnam's 63 provinces/cities. Type the batdongsan slug (tp-hcm, ha-noi, da-nang, ba-ria-vung-tau, ...), the Vietnamese name with or without diacritics (\"Hồ Chí Minh\" or \"Ho Chi Minh\"), a common alias (\"Saigon\", \"HCM\", \"Hanoi\", \"Huế\"), the site's province code (\"SG\", \"HN\"), or the name with \"Thành phố\"/\"Tỉnh\"/\"City\"/\"Province\" around it — matched against the site's own province list, not guessed. An unrecognized name fails the run with a clear error instead of silently returning zero results. For a district or ward, use URL mode with the search URL from the site. Leave empty for a nationwide search. Search mode only.",
            "items": {
              "type": "string"
            }
          },
          "minPrice": {
            "title": "Min price (VND)",
            "minimum": 0,
            "type": "integer",
            "description": "Lowest total price in Vietnamese dong, e.g. 1000000000 for 1 tỷ. For Rent searches this is the monthly rent, e.g. 10000000 for 10 triệu/month. Listings with a negotiable price (Thỏa thuận) are excluded by the site when a price filter is set."
          },
          "maxPrice": {
            "title": "Max price (VND)",
            "minimum": 0,
            "type": "integer",
            "description": "Highest total price in Vietnamese dong, e.g. 3000000000 for 3 tỷ (monthly rent for Rent searches)."
          },
          "negotiablePriceOnly": {
            "title": "Only negotiable-price listings",
            "type": "boolean",
            "description": "Return only listings whose price is \"Giá thỏa thuận\" (negotiable, no published price). Cannot be combined with Min/Max price. Search mode only."
          },
          "minArea": {
            "title": "Min area (m²)",
            "minimum": 0,
            "type": "integer",
            "description": "Smallest floor/land area in square metres."
          },
          "maxArea": {
            "title": "Max area (m²)",
            "minimum": 0,
            "type": "integer",
            "description": "Largest floor/land area in square metres."
          },
          "bedrooms": {
            "title": "Bedrooms",
            "type": "array",
            "description": "Only listings with one of these bedroom counts. Pick several to combine them. \"5+\" is the site's own five-or-more bucket. Leave empty for any.",
            "items": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "4",
                "5"
              ],
              "enumTitles": [
                "1",
                "2",
                "3",
                "4",
                "5+"
              ]
            }
          },
          "directions": {
            "title": "House-facing direction",
            "type": "array",
            "description": "Only listings whose house faces one of these directions (Hướng nhà). Many listings don't state a direction, so this narrows results a lot. Leave empty for any.",
            "items": {
              "type": "string",
              "enum": [
                "East",
                "West",
                "South",
                "North",
                "NorthEast",
                "NorthWest",
                "SouthWest",
                "SouthEast"
              ],
              "enumTitles": [
                "Đông / East",
                "Tây / West",
                "Nam / South",
                "Bắc / North",
                "Đông Bắc / North-east",
                "Tây Bắc / North-west",
                "Tây Nam / South-west",
                "Đông Nam / South-east"
              ]
            }
          },
          "keyword": {
            "title": "Keyword",
            "type": "string",
            "description": "Free-text keyword matched by the site's own search, e.g. a project or street name (\"vinhomes\", \"Nguyễn Hữu Cảnh\"). Leave empty for none."
          },
          "sortBy": {
            "title": "Sort by",
            "enum": [
              "Default",
              "VerifiedFirst",
              "PriceLowToHigh",
              "PriceHighToLow",
              "PricePerM2LowToHigh",
              "PricePerM2HighToLow",
              "AreaSmallToLarge",
              "AreaLargeToSmall"
            ],
            "type": "string",
            "description": "Order of results, applied by the site. Default keeps the site's own ranking.",
            "default": "Default"
          },
          "urls": {
            "title": "Search URLs (URL mode)",
            "type": "array",
            "description": "One or more batdongsan.com.vn URLs — a search/category page (city, district, ward, price/area/bedroom-filtered, or 'All property types'), a project page, or a single listing's detail page (-prNNNNNN). Tip: open batdongsan.com.vn in your browser, pick listing type + property type + city + any price/area/bedroom filters, then paste the resulting URL here. Multi-URL supported, mixing shapes freely. If a search/category URL ends with `/pN`, scraping starts at page N and walks forward. A detail URL is fetched directly as one record — no pagination, no wasted retries. A /tags/ topic page (batdongsan.com.vn/tags/ban/...) and the map view (?tpl=map) are walked like a search. A broker/developer/company profile page or a project directory (/du-an-can-ho-chung-cu, which lists projects rather than listings) is skipped with a warning, not silently scraped as empty. See the README's URL shapes table for the full list with examples.",
            "items": {
              "type": "string"
            },
            "default": [
              "https://batdongsan.com.vn/ban-can-ho-chung-cu-tp-hcm",
              "https://batdongsan.com.vn/cho-thue-can-ho-chung-cu-tp-hcm",
              "https://batdongsan.com.vn/ban-can-ho-chung-cu-quan-1",
              "https://batdongsan.com.vn/ban-can-ho-chung-cu-tp-hcm/gia-tu-1-ty-den-2-ty",
              "https://batdongsan.com.vn/nha-dat-ban-ha-noi",
              "https://batdongsan.com.vn/du-an-can-ho-chung-cu-quan-2/the-sun-avenue-pj2065",
              "https://batdongsan.com.vn/ban-can-ho-chung-cu-duong-dao-tri-vlasta-premier-phu-thuan/gio-hang-ngoai-giao-q7-chiet-khau-250tr-tt-15-toi-nhan-nha-ban-giao-full-noi-that-pr46279173",
              "https://batdongsan.com.vn/ban-can-ho-chung-cu-tp-hcm/dt-tu-50m2-den-80m2",
              "https://batdongsan.com.vn/ban-can-ho-chung-cu-tp-hcm/2pn",
              "https://batdongsan.com.vn/ban-nha-rieng-tp-hcm?gtn=3-ty&gcn=8-ty&dtnn=40&dtln=120",
              "https://batdongsan.com.vn/ban-can-ho-chung-cu-quan-7?tpl=map",
              "https://batdongsan.com.vn/tags/ban/ban-can-ho-mini-tp-hcm"
            ]
          },
          "maxPages": {
            "title": "Max pages per search",
            "minimum": 0,
            "type": "integer",
            "description": "How many result pages to walk per city / URL. Batdongsan returns roughly 20 to 30 listings per page. 0 (default) means unlimited: the walk stops naturally once a page comes back empty or repeats listings already collected, or sooner once Max total listings is reached. Set a number only for an explicit page cap below that natural stop.",
            "default": 0
          },
          "maxListings": {
            "title": "Max total listings",
            "minimum": 0,
            "type": "integer",
            "description": "The sole soft cap on the run: stop after this many listings across all cities/URLs. Defaults to 20 so a run stays small unless you raise it. 0 = unlimited (bounded only by the natural stop on Max pages).",
            "default": 20
          },
          "fetchDetails": {
            "title": "Visit each listing's detail page",
            "type": "boolean",
            "description": "Adds GPS latitude/longitude, full description, agent name + phone + profile link, the full specification table (legal status, frontage, access-road width, floors), listing videos, project id, posted date, expiry date, and listing code. Turn off for a faster, cheaper run with just the SERP-level fields (title, price, area, bedrooms, location, photos, verified / pro-agent badges).",
            "default": true
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Vietnam residential proxy is strongly recommended (default). Batdongsan only serves traffic from Vietnam-reachable connections, so a VN residential exit is required for reliable results."
          },
          "resumeFromRunId": {
            "title": "Resume from a prior run",
            "type": "string",
            "description": "Optional. Paste a previous run ID or dataset ID to continue a large walk-all pull: listings already saved by that run are loaded before scraping starts and skipped, so this run only appends new listings (rows marked EXPIRED there are not skipped, so a listing that came back is collected again). Leave empty for a normal fresh run. For recurring daily/weekly monitoring of the same search, use Incremental mode below instead."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns all matching listings as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED listings. Turn on \"Emit unchanged\" or \"Emit expired\" only when you also want those listings returned (and billed). State is kept separately for each mode/listing type/property type/location(s)/URL(s)/filters and detail-fetch setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a prior run above.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode/listing type/property type/location(s)/URL(s)/filters and detail-fetch setting — different searches then never mix state with each other."
          },
          "emitUnchanged": {
            "title": "Emit unchanged listings (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return listings that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired listings (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return listings that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search — not when Max total listings capped it, Resume was used, or a pasted URL started mid-catalogue (a /pN page with N>1). This returns — and bills — extra synthetic rows, which count toward Max total listings (gone listings past that limit stay tracked and are reported on a later run), so leave it off unless you need expiry tracking.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Optional. Fields to exclude when deciding UPDATED vs UNCHANGED in incremental mode, on top of the ones always excluded by default: scrapedAt; agentPhoneToken (a KYC-gated contact token re-minted on every page render, so it differs on every scrape of the same unchanged listing); searchUrl, pageNumber and position (where the listing happened to sit in this run's results); and postedLabel (the site's relative \"posted N days ago\" text, which changes daily). Add a top-level field name (e.g. \"agentAvatar\") or a dotted path into a nested field (e.g. \"specs.Ngày đăng\") for any other field that rotates/reorders without a real content change on your use case. Listed fields are still returned in the output — only excluded from change detection and from changedFields.",
            "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}