{
  "openapi": "3.0.1",
  "info": {
    "title": "99.co Property Scraper (Indonesia & Singapore)",
    "description": "Scrape property listings, prices and agents from 99.co across Indonesia and Singapore. Six modes: Indonesian search with price history and coordinates, full listing detail with POI and Q&A, location facets, Singapore search and detail, and median HDB resale prices. No login needed.",
    "version": "0.0",
    "x-build-id": "33icUh2HaU4X4lNDf"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/fanndev~99co-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-fanndev-99co-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/fanndev~99co-scraper/runs": {
      "post": {
        "operationId": "runs-sync-fanndev-99co-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/fanndev~99co-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-fanndev-99co-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",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "idSearch",
              "idListingDetail",
              "idLocations",
              "sgSearch",
              "sgListingDetail",
              "sgHdbResalePrices"
            ],
            "type": "string",
            "description": "Which surface to scrape. 99.co runs two different applications on one domain, so modes are split by market: the id-prefixed ones cover Indonesia and the sg-prefixed ones cover Singapore. Each mode reads one input list.",
            "default": "idSearch"
          },
          "idSearchTargets": {
            "title": "Indonesia: search targets",
            "type": "array",
            "description": "Indonesian search paths, used by idSearch and idLocations. Must start with 'jual' (for sale) or 'sewa' (for rent), optionally followed by a property type and a location, e.g. 'jual/rumah', 'sewa/apartemen', 'jual/rumah/jakarta-selatan'. A full https://www.99.co/id/... URL also works. The urlSlug field from idLocations can be pasted straight in here.",
            "items": {
              "type": "string"
            }
          },
          "idListingSlugs": {
            "title": "Indonesia: listing slugs or URLs",
            "type": "array",
            "description": "Indonesian listing slugs for idListingDetail, e.g. 'rumah-dijual-24miliar-cilandak-cp-54195423533', or the full https://www.99.co/id/properti/... URL. The url field of any idSearch record can be fed straight back in here.",
            "items": {
              "type": "string"
            }
          },
          "sgSearchTargets": {
            "title": "Singapore: search targets",
            "type": "array",
            "description": "Singapore search paths for sgSearch, relative to /singapore, e.g. 'rent', 'sale', 'rent/areas/bedok', 'rent/2-bedrooms'. A full https://www.99.co/singapore/... URL also works.",
            "items": {
              "type": "string"
            }
          },
          "sgListingUrls": {
            "title": "Singapore: listing URLs",
            "type": "array",
            "description": "Full Singapore listing URLs for sgListingDetail, e.g. https://www.99.co/singapore/rooms/property/335a-yishun-street-31-hdb-PBi5f6nP6qK47XRZKadBXm. The listingUrl field of any sgSearch record works here.",
            "items": {
              "type": "string"
            }
          },
          "maxPages": {
            "title": "Max pages per target",
            "minimum": 1,
            "maximum": 200,
            "type": "integer",
            "description": "How many result pages to walk per search target. Indonesian search is HARD CAPPED at 9: from page 10 onward 99.co answers with a Cloudflare managed challenge that no TLS fingerprint gets past, so a higher value is clamped and a warning is logged. Singapore has no such cap. Indonesian pages carry about 31 entries, Singapore about 36.",
            "default": 5
          },
          "maxItemsPerTarget": {
            "title": "Max items per target",
            "minimum": 0,
            "type": "integer",
            "description": "Hard cap on records emitted per search target. Leave at 0 for no cap beyond maxPages.",
            "default": 0
          },
          "includeProjectPlacements": {
            "title": "Indonesia: include project placements",
            "type": "boolean",
            "description": "Indonesian result pages interleave ordinary listings ('secondary') with paid developer and project placements ('primary'). Both are emitted by default, tagged with groupType. Turn this off to keep only ordinary listings - worth doing when counting a market, since placements are paid inventory rather than organic supply.",
            "default": true
          },
          "minPrice": {
            "title": "Indonesia: minimum price (IDR)",
            "minimum": 0,
            "type": "integer",
            "description": "Lower price bound for Indonesian search, in rupiah. Sent as harga_min, which is verified to reach the backend filter. Price bands are the main way to split a query that would otherwise exceed the 9-page ceiling."
          },
          "maxPrice": {
            "title": "Indonesia: maximum price (IDR)",
            "minimum": 0,
            "type": "integer",
            "description": "Upper price bound for Indonesian search, in rupiah. Sent as harga_maks."
          },
          "minBedrooms": {
            "title": "Indonesia: minimum bedrooms",
            "minimum": 0,
            "type": "integer",
            "description": "Minimum bedroom count for Indonesian search. Sent as kamar_tidur_min."
          },
          "propertyType": {
            "title": "Indonesia: property type",
            "type": "string",
            "description": "Property type filter for Indonesian search, sent as tipe_properti, e.g. 'rumah', 'apartemen', 'tanah', 'ruko'. Usually simpler to put the type in the search path instead ('jual/apartemen')."
          },
          "sort": {
            "title": "Indonesia: sort order",
            "type": "string",
            "description": "Sort order for Indonesian search, sent as urut, e.g. 'termurah' (cheapest first) or 'terbaru' (newest first). Changing the sort is another way to reach different inventory within the 9-page ceiling."
          },
          "concurrency": {
            "title": "Concurrency",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Parallel requests for the detail modes. Search modes always walk pages in order because each page's referer is the previous page. Kept low by default: 99.co sits behind Cloudflare and pages are over 1 MB.",
            "default": 3
          },
          "requestDelaySecs": {
            "title": "Delay between requests",
            "minimum": 0,
            "maximum": 30,
            "type": "integer",
            "description": "Minimum seconds between requests. Cloudflare scores this origin more aggressively than a plain server-rendered site, and the pages are large, so a small floor costs little. Set to 0 to disable pacing.",
            "default": 1
          },
          "maxRetries": {
            "title": "Max retries",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Attempts per request before giving up. Each retry backs off exponentially with jitter and rotates to the next TLS impersonation profile. The client always gives the ladder at least one full lap, since a challenge is fingerprint-shaped.",
            "default": 4
          },
          "requestTimeoutSecs": {
            "title": "Request timeout",
            "minimum": 10,
            "maximum": 300,
            "type": "integer",
            "description": "Per-request timeout in seconds. 99.co pages are 1-1.6 MB, so do not set this too low.",
            "default": 45
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Optional but recommended at volume. 99.co is behind Cloudflare and escalates to a managed challenge on some paths, so residential exit addresses hold up better than datacenter ones over a long run. If proxy setup fails the run continues direct and says so rather than failing.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            }
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}