# serve Property Scraper — Korea Real Estate Data & API (`sian.agency/serve-property-scraper`) Actor

serve.co.kr (부동산써브) scraper & Korea real estate data API. Sale, jeonse & monthly-rent listings: price, deal type, area, rooms, floor, direction, geo, agency contact, cross-portal ids — clean JSON/CSV, one row per listing. Fast overview or full detail. No account needed. 부동산써브 매물 데이터·부동산 API.

- **URL**: https://apify.com/sian.agency/serve-property-scraper.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** Real estate, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 overview listing extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## serve Property Scraper — Korea Real Estate Data & API 🏠

[![SIÁN Agency Store](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Fazwaz Property Scraper](https://img.shields.io/badge/Store-Fazwaz%20Property%20Scraper-1AE392)](https://apify.com/sian.agency/fazwaz-property-scraper?fpr=sian) [![Immobiliare.it Scraper](https://img.shields.io/badge/Store-Immobiliare.it%20Scraper-1AE392)](https://apify.com/sian.agency/immobiliare-property-scraper?fpr=sian) [![Bayut Property Scraper](https://img.shields.io/badge/Store-Bayut%20Property%20Scraper-93D500)](https://apify.com/sian.agency/bayut-property-scraper?fpr=sian)

#### 🎉 Turn serve.co.kr (부동산써브) into clean, structured data — one row per listing, ready for analysis
##### For real-estate analysts, investors, relocation agents, and data teams working the South Korean property market

---

### 📋 Overview

**Need South Korean sale, jeonse and monthly-rent listings as clean data instead of clicking around a map?** This scraper turns serve.co.kr search results into structured JSON/CSV — one clean record per listing, with prices normalised to KRW, deal type, area, rooms, floor, geo coordinates, agency contact and cross-portal ids.

**Why analysts and agencies choose us:**
- ✅ **One clean row per listing** — every result becomes a structured record, no nested mess
- ⚡ **Fast & lightweight** — direct JSON extraction, no slow headless browser, no proxy overhead
- 🎯 **55+ data points** — price (KRW + raw 만원), deal type, supply/exclusive/contract area, rooms, baths, floor, direction, geo, agency name & phone, building approval date
- 📡 **Cross-portal ids** — surfaces the matching Naver / KB Land / Dabang article ids, so you can join serve data to other Korean portals
- 💰 **Pay-per-result** — only pay for listings you actually receive — transparent and cheap
- 💎 **Two depths** — fast *overview* for whole-market sweeps, full *detail* for parking, heating, household count and the full street address
- ✨ **Four ways in** — by legal-dong code, by pasted search URL, by automatic region crawl, or by article id

---

### ✨ Features

- 🏢 **Listings, done right** — clean per-listing records, one row per unit
- 💰 **Money normalised** — man-won values become whole KRW *and* keep the raw integer
- 📐 **Price-per-m² built in** — yield and comparison math ready out of the box
- 🗺️ **Region crawl** — auto-discover every neighbourhood with listings in a region and sweep them
- 🔎 **Detail enrichment** — parking count, heating method & fuel, household count, building approval date, full street address
- 📞 **Agency contact** — agency name, representative, landline and mobile on every listing
- 🔗 **Cross-portal join keys** — Naver / KB / Dabang article ids on each record
- 🔗 **Paste-a-URL mode** — paste a serve listing URL and the actor reads the neighbourhood + filters
- 📦 **Clean exports** — JSON, CSV, Excel straight from the dataset
- 🌐 **Optional Korea proxy** — off by default, available as a one-click escape hatch

---

### 🎬 Quick Start

Pick a scrape mode (overview or detail), choose how to find listings (legal-dong code, search URL, region crawl, or article id), and run. Results land in a clean dataset you can export as JSON, CSV or Excel.

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~serve-property-scraper/runs?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"scrapeMode": "overview", "searchMode": "byLdong", "ldongCodes": ["4113511100"]}'
````

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose your listings

Give a legal-dong code (e.g. `4113511100`), paste a serve search URL, turn on region crawl, or list specific article ids.

#### Step 2: Pick a depth

**Overview** for fast, near-complete listing rows. **Detail** to also pull parking, heating, household count and the full address.

#### Step 3: Run & export

Start the run and download your dataset as JSON, CSV, or Excel.

**That's it! In under a minute, you'll have:**

- A clean dataset of South Korean property listings
- Prices normalised to KRW with price-per-m² computed
- Agency contact and cross-portal ids ready to join

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| scrapeMode | string | No | `overview` (fast) or `detail` (enriched) |
| searchMode | string | No | `byLdong`, `bySearchUrl`, `byCrawl`, or `byArticleId` |
| ldongCodes | array | No | Legal-dong codes to list (byLdong) |
| searchUrls | array | No | serve.co.kr listing URLs carrying `ldongCd` (bySearchUrl) |
| articleIds | array | No | `atclNo:CATEGORY` pairs for detail (byArticleId) |
| category | string | No | `apt`, `officetel`, `house`, `presale`, `all`, or a detail code (OFT/APT/RED/LOT) |
| order | string | No | `default`, `newest`, `price`, `area` |
| maxResults | integer | No | Max listings per run (FREE: 25, PAID: unlimited) |

**Example — overview by legal-dong:**

```json
{
  "scrapeMode": "overview",
  "searchMode": "byLdong",
  "ldongCodes": ["4113511100"],
  "category": "officetel",
  "maxResults": 100
}
```

**Example — detail by article id:**

```json
{
  "scrapeMode": "detail",
  "searchMode": "byArticleId",
  "articleIds": ["333750957:OFT"]
}
```

***

### 📤 Output

Results are saved to the Apify dataset with **55+ fields** including:

| Field | Type | Description |
|-------|------|-------------|
| listingId | string | serve article number (atclNo) |
| url | string | Canonical serve.co.kr listing URL |
| deal\_type | string | 매매 (sale) / 전세 (jeonse) / 월세 (monthly) |
| category | string | 오피스텔 / 아파트 / 주택 / 분양권 |
| complex\_name | string | Apartment or building name |
| price\_krw | number | Sale price or jeonse deposit in whole KRW |
| monthly\_rent\_krw | number | Monthly rent in whole KRW |
| price\_per\_sqm\_krw | number | Computed price per square metre |
| exclusive\_area\_sqm | number | Exclusive (net) area in m² |
| rooms / bathrooms | number | Room & bathroom counts |
| floor / floors\_total | number | Unit floor & building total floors |
| sido / sigungu / dong | string | Province, city/district, neighbourhood |
| address | string | Full street address (detail) |
| agency\_name / agency\_phone | string | Listing agency & phone |
| naver\_atcl\_no / kb\_atcl\_no / dabang\_atcl\_no | string | Cross-portal join keys |

**Example record:**

```json
{
  "listingId": "333750957",
  "url": "https://www.serve.co.kr/good/map?m=1&lat=37.35108&lng=127.10487&atcl=333750957",
  "source": "overview",
  "deal_type": "매매",
  "category": "오피스텔",
  "complex_name": "코오롱트리폴리스",
  "price_krw": 1200000000,
  "price_manwon": 120000,
  "exclusive_area_sqm": 171.19,
  "price_per_sqm_krw": 7009755,
  "rooms": 4,
  "bathrooms": 2,
  "floor": 11,
  "floors_total": 37,
  "sido": "경기도",
  "sigungu": "성남시 분당구",
  "dong": "금곡동",
  "agency_name": "프라임공인중개사사무소",
  "agency_phone": "031-728-3377",
  "naver_atcl_no": "2633107628",
  "currency": "KRW"
}
```

***

### 💼 Use Cases & Examples

#### 1. Korea Rent & Sale Market Research

**Analysts mapping prices across a Seoul district or Gyeonggi neighbourhood.**

**Input:** A legal-dong code or region crawl
**Output:** Every listing with price, area and price/m²
**Use:** Build rent-by-area and sale-by-area benchmarks over time

#### 2. Property Investment Analysis

**Investors comparing gross yields across buildings and unit types.**

**Input:** Officetel or apartment category in a target area
**Output:** Sale price, monthly rent, lease deposit, area, price/m²
**Use:** Compute cap rates and shortlist undervalued units

#### 3. Real-Estate Lead Generation

**Agencies sourcing listing-agent contacts at scale.**

**Input:** A region crawl across target neighbourhoods
**Output:** Agency name, representative, landline and mobile per listing
**Use:** Build agent outreach lists for partnerships or buy-side mandates

#### 4. Relocation & Tenant Search

**Relocation agents shortlisting rentals with deposit and area.**

**Input:** A neighbourhood + monthly-rent category
**Output:** Rent, lease deposit, rooms, floor, direction, address
**Use:** Hand clients a clean comparison sheet in minutes

#### 5. Cross-Portal Data Joins

**Data teams unifying Korean property feeds.**

**Input:** Overview or detail across a region
**Output:** Naver / KB / Dabang article ids on every record
**Use:** Deduplicate and join serve listings to other Korean portals

#### 6. Price & Inventory Monitoring

**Teams tracking new inventory and price moves.**

**Input:** A scheduled region crawl
**Output:** Fresh listings with registration date
**Use:** Detect new supply and price changes week over week

***

### 🔗 Integration Examples

#### JavaScript/Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/serve-property-scraper').call({
  scrapeMode: 'overview',
  searchMode: 'byLdong',
  ldongCodes: ['4113511100'],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/serve-property-scraper').call(
    run_input={
        'scrapeMode': 'overview',
        'searchMode': 'byLdong',
        'ldongCodes': ['4113511100'],
    }
)

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item)
```

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~serve-property-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"scrapeMode": "overview", "searchMode": "byLdong", "ldongCodes": ["4113511100"]}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: Schedule or webhook
2. **HTTP Request**: Call the actor API
3. **Process**: Handle the JSON results
4. **Action**: Save to a sheet, notify a channel, or push to your CRM

***

### 📊 Performance & Pricing

#### FREE Tier (Try It Now)

- **25 listings** per run — full feature access, same quality
- No credit card required
- Perfect for testing and small projects

#### PAID Tier (Production Ready)

- **Unlimited** listings per run
- Faster processing, no delays
- Pay-per-result: only charged for listings you actually receive

💰 **Cheap, transparent pricing** — a low per-listing overview rate, with detail enrichment only when you ask for it.

🔗 [View current pricing](https://apify.com/sian.agency/serve-property-scraper?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: How many listings can I scrape?**
A: FREE tier: 25 per run. PAID tier: unlimited.

**Q: What's the difference between overview and detail?**
A: Overview rows are already ~85% complete (price, area, rooms, floor, geo, agency). Detail adds parking, heating, household count, building approval date and the full street address — at one extra request per listing.

**Q: What output formats are available?**
A: JSON, CSV, Excel — export directly from the Apify dataset.

**Q: Do I need a proxy or account?**
A: No. The actor runs without an account or proxy. A Korea residential proxy is available as an optional one-click escape hatch.

**Q: How do I find a legal-dong code?**
A: Use the **region crawl** mode to discover neighbourhoods automatically, or copy the `ldongCd` from a serve.co.kr listing request.

**Q: Is this legal?**
A: Yes — we only extract publicly available data. See the legal section below.

***

### 🐛 Troubleshooting

**No listings returned**

- Check the legal-dong code is valid, or switch to **region crawl** mode
- Some neighbourhoods have few or no active listings — try a denser area

**Detail run skips some listings**

- Detail needs both the article id and its category code; use `atclNo:CATEGORY` (e.g. `333750957:OFT`) or set **Category** to a single code

**Run hit the FREE cap**

- FREE runs are capped at 25 listings — upgrade for unlimited results

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

***

### ™️ Trademark Disclaimer

serve.co.kr and 부동산써브 are trademarks of their respective owners. This actor is an independent tool and is **not** affiliated with, endorsed by, or sponsored by serve.co.kr or its operators. All product names, logos, and brands are property of their respective owners and are used for identification purposes only.

***

### 🤝 Support

[![Telegram Support](https://img.shields.io/badge/Telegram-Support%20Group-0088cc?logo=telegram)](https://t.me/+vyh1sRE08sAxMGRi)

**Join our active support community**

- For issues or questions, open an issue in the actor's repository
- Check [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- 📧 <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Actor input Schema

## `scrapeMode` (type: `string`):

🧭 **OVERVIEW** (cheap, primary): one row per listing from serve's listing API — already ~85% complete with price, deal type, category, areas, rooms, floor, geo, agency contact and cross-portal ids.

🔎 **DETAIL** (enrich): also fetches each listing's full record — parking, heating, households, building approval date and the full street address. Detail merges overview + detail into one record.

## `searchMode` (type: `string`):

🔀 How listings are discovered.

- **byLdong** — give one or more legal-dong codes (ldongCd).
- **bySearchUrl** — paste a serve.co.kr listing URL that carries an `ldongCd` param.
- **byCrawl** — automatically sweep a region (Seoul metro by default) and visit every neighbourhood with listings.
- **byArticleId** — fetch specific listings directly as `atclNo:CATEGORY` (DETAIL only).

## `ldongCodes` (type: `array`):

📍 **BY LEGAL-DONG:** One or more legal-dong codes (ldongCd) to list. Example: `4113511100` = 분당 금곡동, `1168010600` = 강남 대치동.

💡 **TIP:** Find an ldongCd by opening a neighbourhood on serve.co.kr's map and copying the `ldongCd` from the listing request, or use the **By region crawl** mode to discover them automatically.

## `searchUrls` (type: `array`):

🔗 **BY SEARCH URL:** Paste one or more serve.co.kr listing URLs that include an `ldongCd` query parameter. Any supported serve filter present in the URL is preserved.

💡 **TIP:** Example — `https://www.serve.co.kr/good/v1/map/getAtclList?ldongCd=4113511100`

## `articleIds` (type: `array`):

🏠 **BY ARTICLE ID (DETAIL ONLY):** Specific listings as `atclNo:CATEGORY` pairs — the category code is required by serve's detail API. Example: `333750957:OFT`. Bare ids work if you set **Category** to a single code (OFT / APT / RED / LOT).

💡 Category codes: OFT = officetel, APT = apartment, RED = house/villa, LOT = presale.

## `category` (type: `string`):

🏷️ Property group filter (overview), or the detail category code for bare article ids.

- Friendly groups: `apt` (아파트), `officetel` (오피스텔), `house` (주택/빌라), `presale` (분양권), `all`.
- Single detail codes: `OFT`, `APT`, `RED`, `LOT`.

Leave blank for all categories.

## `order` (type: `string`):

↕️ Result sort order: `default`, `newest`, `price`, `area` (or serve's numeric `orderCd`). Leave blank for the default order.

## `maxResults` (type: `integer`):

🔢 Maximum listings to return per run. **FREE users:** capped at 25 · **PAID users:** unlimited.

## `maxRecordsPerDong` (type: `integer`):

📄 Maximum listings to pull from a single legal-dong before moving on.

## `maxDongs` (type: `integer`):

🗺️ **BY REGION CRAWL:** Maximum neighbourhoods (legal-dongs) to visit during a region sweep.

## `minArticles` (type: `integer`):

🔢 **BY REGION CRAWL:** Skip neighbourhoods with fewer than this many listings.

## `drcCdListStr` (type: `string`):

🧭 serve's direction filter (`drcCdListStr`), carried verbatim.

## `maxHhcnt` (type: `string`):

🏘️ serve's max-households filter (`maxHhcnt`), carried verbatim.

## `maxCmplxUseAprvDt` (type: `string`):

📅 serve's max use-approval-date filter (`maxCmplxUseAprvDt`), carried verbatim.

## `floorExpsrListStr` (type: `string`):

🏬 serve's floor-exposure filter (`floorExpsrListStr`), carried verbatim.

## `useProxy` (type: `boolean`):

🌐 Route requests through a Korea residential proxy. **Off by default** — serve.co.kr's listing APIs are reachable without a proxy, so leaving this off keeps runs fast and cheap. Enable only if you hit a rate-limit or geo-block.

## Actor input object example

```json
{
  "scrapeMode": "overview",
  "searchMode": "byLdong",
  "ldongCodes": [
    "4113511100"
  ],
  "maxResults": 100,
  "maxRecordsPerDong": 60,
  "maxDongs": 5,
  "minArticles": 1,
  "useProxy": false
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped serve.co.kr listings as a clean JSON/CSV dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "ldongCodes": [
        "4113511100"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/serve-property-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "ldongCodes": ["4113511100"] }

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/serve-property-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "ldongCodes": [
    "4113511100"
  ]
}' |
apify call sian.agency/serve-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=sian.agency/serve-property-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "serve Property Scraper — Korea Real Estate Data & API",
        "description": "serve.co.kr (부동산써브) scraper & Korea real estate data API. Sale, jeonse & monthly-rent listings: price, deal type, area, rooms, floor, direction, geo, agency contact, cross-portal ids — clean JSON/CSV, one row per listing. Fast overview or full detail. No account needed. 부동산써브 매물 데이터·부동산 API.",
        "version": "1.0",
        "x-build-id": "mg5MgJOmxLDhDE7XX"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/sian.agency~serve-property-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-sian.agency-serve-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/sian.agency~serve-property-scraper/runs": {
            "post": {
                "operationId": "runs-sync-sian.agency-serve-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/sian.agency~serve-property-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-sian.agency-serve-property-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "scrapeMode": {
                        "title": "🧭 Scrape mode",
                        "enum": [
                            "overview",
                            "detail"
                        ],
                        "type": "string",
                        "description": "🧭 **OVERVIEW** (cheap, primary): one row per listing from serve's listing API — already ~85% complete with price, deal type, category, areas, rooms, floor, geo, agency contact and cross-portal ids.\n\n🔎 **DETAIL** (enrich): also fetches each listing's full record — parking, heating, households, building approval date and the full street address. Detail merges overview + detail into one record.",
                        "default": "overview"
                    },
                    "searchMode": {
                        "title": "🔀 Search mode",
                        "enum": [
                            "byLdong",
                            "bySearchUrl",
                            "byCrawl",
                            "byArticleId"
                        ],
                        "type": "string",
                        "description": "🔀 How listings are discovered.\n\n- **byLdong** — give one or more legal-dong codes (ldongCd).\n- **bySearchUrl** — paste a serve.co.kr listing URL that carries an `ldongCd` param.\n- **byCrawl** — automatically sweep a region (Seoul metro by default) and visit every neighbourhood with listings.\n- **byArticleId** — fetch specific listings directly as `atclNo:CATEGORY` (DETAIL only).",
                        "default": "byLdong"
                    },
                    "ldongCodes": {
                        "title": "📍 Legal-dong codes",
                        "type": "array",
                        "description": "📍 **BY LEGAL-DONG:** One or more legal-dong codes (ldongCd) to list. Example: `4113511100` = 분당 금곡동, `1168010600` = 강남 대치동.\n\n💡 **TIP:** Find an ldongCd by opening a neighbourhood on serve.co.kr's map and copying the `ldongCd` from the listing request, or use the **By region crawl** mode to discover them automatically.",
                        "default": [
                            "4113511100"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchUrls": {
                        "title": "🔗 Search URLs",
                        "type": "array",
                        "description": "🔗 **BY SEARCH URL:** Paste one or more serve.co.kr listing URLs that include an `ldongCd` query parameter. Any supported serve filter present in the URL is preserved.\n\n💡 **TIP:** Example — `https://www.serve.co.kr/good/v1/map/getAtclList?ldongCd=4113511100`",
                        "items": {
                            "type": "string"
                        }
                    },
                    "articleIds": {
                        "title": "🏠 Article ids",
                        "type": "array",
                        "description": "🏠 **BY ARTICLE ID (DETAIL ONLY):** Specific listings as `atclNo:CATEGORY` pairs — the category code is required by serve's detail API. Example: `333750957:OFT`. Bare ids work if you set **Category** to a single code (OFT / APT / RED / LOT).\n\n💡 Category codes: OFT = officetel, APT = apartment, RED = house/villa, LOT = presale.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "category": {
                        "title": "🏷️ Category",
                        "type": "string",
                        "description": "🏷️ Property group filter (overview), or the detail category code for bare article ids.\n\n- Friendly groups: `apt` (아파트), `officetel` (오피스텔), `house` (주택/빌라), `presale` (분양권), `all`.\n- Single detail codes: `OFT`, `APT`, `RED`, `LOT`.\n\nLeave blank for all categories."
                    },
                    "order": {
                        "title": "↕️ Sort order",
                        "type": "string",
                        "description": "↕️ Result sort order: `default`, `newest`, `price`, `area` (or serve's numeric `orderCd`). Leave blank for the default order."
                    },
                    "maxResults": {
                        "title": "🔢 Max results",
                        "minimum": 1,
                        "type": "integer",
                        "description": "🔢 Maximum listings to return per run. **FREE users:** capped at 25 · **PAID users:** unlimited.",
                        "default": 100
                    },
                    "maxRecordsPerDong": {
                        "title": "📄 Max records per neighbourhood",
                        "minimum": 1,
                        "type": "integer",
                        "description": "📄 Maximum listings to pull from a single legal-dong before moving on.",
                        "default": 60
                    },
                    "maxDongs": {
                        "title": "🗺️ Max neighbourhoods (crawl)",
                        "minimum": 1,
                        "type": "integer",
                        "description": "🗺️ **BY REGION CRAWL:** Maximum neighbourhoods (legal-dongs) to visit during a region sweep.",
                        "default": 5
                    },
                    "minArticles": {
                        "title": "🔢 Min listings per neighbourhood (crawl)",
                        "minimum": 1,
                        "type": "integer",
                        "description": "🔢 **BY REGION CRAWL:** Skip neighbourhoods with fewer than this many listings.",
                        "default": 1
                    },
                    "drcCdListStr": {
                        "title": "🧭 Direction filter",
                        "type": "string",
                        "description": "🧭 serve's direction filter (`drcCdListStr`), carried verbatim."
                    },
                    "maxHhcnt": {
                        "title": "🏘️ Max households",
                        "type": "string",
                        "description": "🏘️ serve's max-households filter (`maxHhcnt`), carried verbatim."
                    },
                    "maxCmplxUseAprvDt": {
                        "title": "📅 Max approval date",
                        "type": "string",
                        "description": "📅 serve's max use-approval-date filter (`maxCmplxUseAprvDt`), carried verbatim."
                    },
                    "floorExpsrListStr": {
                        "title": "🏬 Floor exposure filter",
                        "type": "string",
                        "description": "🏬 serve's floor-exposure filter (`floorExpsrListStr`), carried verbatim."
                    },
                    "useProxy": {
                        "title": "🌐 Use Korea residential proxy",
                        "type": "boolean",
                        "description": "🌐 Route requests through a Korea residential proxy. **Off by default** — serve.co.kr's listing APIs are reachable without a proxy, so leaving this off keeps runs fast and cheap. Enable only if you hit a rate-limit or geo-block.",
                        "default": false
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
