# Etagi Scraper — Russia Property Data & API (`sian.agency/etagi-property-scraper`) Actor

Etagi scraper & real estate data API for Russia's largest property-agency network. Sale & rent listings across many Russian cities: price (RUB), price/m², rooms, area, floor, building year, GPS, metro, photos, new-build complex — clean JSON/CSV.

- **URL**: https://apify.com/sian.agency/etagi-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 $2.50 / 1,000 overview listings

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

## Etagi Scraper — Russia Property Data & API 🇷🇺🏠

[![SIÁN Agency Store](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Yandex Realty Scraper](https://img.shields.io/badge/Store-Yandex%20Realty-FF0000)](https://apify.com/sian.agency/yandex-realty-scraper?fpr=sian) [![Cian Property Scraper](https://img.shields.io/badge/Store-Cian%20Property-0468FF)](https://apify.com/sian.agency/cian-property-scraper?fpr=sian) [![Zillow Property Scraper](https://img.shields.io/badge/Store-Zillow%20Property-1F4E79)](https://apify.com/sian.agency/zillow-property-scraper?fpr=sian)

#### 🎉 The fast, no-code Etagi data API — sale & rent listings across Russia with price/m², GPS, metro & new-build (ЖК) data, no Etagi API key required
##### For investors, analysts, agencies and proptech teams who need clean structured Russian real-estate data at scale

---

### 📋 Overview

**Pull every Etagi listing into a clean dataset in minutes** — Etagi is Russia's largest real-estate agency network, covering sale and rent, new-builds and secondary, across dozens of cities. This scraper turns its public listings into structured JSON/CSV/Excel: price in rubles, price per square meter, rooms, area, floor, building year, GPS coordinates, nearest metro, photos and the new-build complex (ЖК) name.

**Why professionals choose us:**
- ✅ **Deterministic city targeting**: pick any Russian city by name and get exactly that city's inventory — no guessing, no IP roulette.
- ⚡ **Fast & cheap Overview mode**: every core field straight from the listings feed, billed per result.
- 🎯 **High coverage**: price, geo and photos on virtually every record; 40+ structured fields per listing.
- 💸 **Pay-per-result pricing**: you're only charged for listings actually extracted — and never until your input is validated.
- 💎 **Sale + rent in one place**: switch between buy and rent with a single field; rent rows add deposit, rental period and online-rent flags.
- ✨ **New-build (ЖК) intelligence**: complex name, completion year/quarter and new-building flags for off-plan tracking.

---

### ✨ Features

- 🏙️ **City selection** — search any Russian city by its Etagi slug (Tyumen, Moscow, St. Petersburg, Ekaterinburg, Kazan, and more).
- 🤝 **Sale or rent** — one toggle covers both deal types with the right fields for each.
- 🏠 **Object types** — flats, houses, commercial, land and garages.
- 🎚️ **Rich filters** — price, area, rooms, floor and build-year ranges, applied at the source.
- ↕️ **Sorting** — featured, price, area, newest, or price per m².
- 🔢 **Tiered limits** — try free, scale unlimited on the paid tier.
- 📍 **Geo & metro** — GPS latitude/longitude plus nearest metro and walk time.
- 🖼️ **Media** — main photo, photo count, virtual-tour and video flags.
- 🔁 **Detail refresh** — re-fetch any property by its listing URL for a fresh full record.
- 📤 **Clean exports** — JSON, CSV and Excel straight from the Apify dataset.

---

### 🎬 Quick Start

Pick a city, choose sale or rent, and run. Results stream into the dataset as clean rows you can export to JSON, CSV or Excel. Start in Overview mode for the fast, cheap path.

```bash
curl -X POST "https://api.apify.com/v2/acts/sian.agency~etagi-property-scraper/runs?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"scrapeMode": "overview", "city": "tyumen", "deal": "sale", "maxResults": 50}'
````

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose your scrape depth

**Overview** for the fast, cheap path (every core field from the listings feed) or **Detail** to refresh exact properties by their URL.

#### Step 2: Pick your city, deal & filters

Set the city slug, choose sale or rent, and optionally narrow by price, area, rooms, floor or build year.

#### Step 3: Set a limit & run

Cap the run with **Max results**, hit **Start**, and export your dataset.

**That's it! In a couple of minutes, you'll have:**

- A structured dataset of Russian property listings
- Price, geo, metro and media on every record
- Clean JSON/CSV/Excel ready for analysis or import

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `scrapeMode` | string | No | `overview` (fast & cheap) or `detail` (refresh by URL). Default `overview`. |
| `city` | string | No | Russian city slug, e.g. `tyumen`, `moskva`, `ekaterinburg`. Default `tyumen`. |
| `deal` | string | No | `sale` or `rent`. Default `sale`. |
| `objectType` | string | No | `flat`, `house`, `commercial`, `land`, `garage`. Default `flat`. |
| `listingUrls` | array | No | Detail mode: specific Etagi listing URLs to refresh. |
| `sort` | string | No | `default`, `price_asc`, `price_desc`, `area_asc`, `area_desc`, `date_desc`, `price_m2_asc`. |
| `priceMin` / `priceMax` | integer | No | Price range filter (RUB). |
| `areaMin` / `areaMax` | integer | No | Total-area range filter (m²). |
| `rooms` | integer | No | Exact room count (0 = studio). |
| `floorMin` / `floorMax` | integer | No | Floor range filter. |
| `yearMin` / `yearMax` | integer | No | Build-year range filter. |
| `maxResults` | integer | No | Max listings per run. FREE: 25; PAID: unlimited. |

**Example — Moscow rentals under 60,000 ₽, cheapest first:**

```json
{
  "scrapeMode": "overview",
  "city": "moskva",
  "deal": "rent",
  "priceMax": 60000,
  "sort": "price_asc",
  "maxResults": 100
}
```

**Example — refresh specific properties by URL:**

```json
{
  "scrapeMode": "detail",
  "listingUrls": [
    "https://tyumen.etagi.com/realty/12938989/",
    "https://moskva.etagi.com/realty_rent/12987947/"
  ]
}
```

***

### 📤 Output

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

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Public Etagi object id |
| `url` | string | Canonical listing URL |
| `deal_type` | string | `sale` or `rent` |
| `object_type` | string | Property type (e.g. flat) |
| `price` | integer | Price in rubles (RUB) |
| `price_per_sqm` | integer | Price per square meter |
| `rooms` | integer | Number of rooms (0 = studio) |
| `area_total_sqm` | number | Total area in m² |
| `floor` / `floors_total` | integer | Floor and total floors |
| `building_year` | integer | Construction year |
| `city` / `district` / `street` | string | Location breakdown |
| `latitude` / `longitude` | number | GPS coordinates |
| `metro_name` / `metro_time_min` | string / integer | Nearest metro + walk time |
| `newcomplex_name` | string | New-build complex (ЖК) name |
| `deposit` / `rental_period` | integer | Rent-only fields |
| `main_photo` / `photo_count` | string / integer | Media |

**Example:**

```json
{
  "id": "12938989",
  "url": "https://tyumen.etagi.com/realty/12938989/",
  "deal_type": "sale",
  "object_type": "flat",
  "price": 7900000,
  "currency": "RUB",
  "price_per_sqm": 141071,
  "rooms": 2,
  "area_total_sqm": 56,
  "floor": 7,
  "floors_total": 24,
  "building_year": 2020,
  "city": "Тюмень",
  "district": "Дом Обороны",
  "street": "Полевая",
  "latitude": 57.17264,
  "longitude": 65.483465,
  "newcomplex_name": "Озёрный парк",
  "is_new_building": true,
  "main_photo": "https://cdn.example/photo.jpeg",
  "photo_count": 33,
  "source": "overview"
}
```

***

### 💼 Use Cases & Examples

#### 1. Market research & price benchmarking

**Analysts** tracking price-per-m² trends across Russian cities.
**Input:** a city + sale, sorted by price/m². **Output:** structured price + area data. **Use:** build city-level price indices.

#### 2. Investment sourcing

**Investors** hunting undervalued flats and new-builds.
**Input:** price and area filters per city. **Output:** ranked inventory with ЖК data. **Use:** shortlist deals by yield potential.

#### 3. Agency & broker lead generation

**Agencies** mapping the competitive landscape.
**Input:** a city + deal type. **Output:** listings with office and agent ids. **Use:** territory and inventory analysis.

#### 4. New-build (ЖК) tracking

**Proptech teams** monitoring off-plan supply.
**Input:** sale + new-building filters. **Output:** complex names + completion year/quarter. **Use:** track pipeline by developer.

#### 5. Rental-yield research

**Investors** comparing rent vs. sale economics.
**Input:** rent and sale runs for the same city. **Output:** price, deposit and area. **Use:** compute gross rental yields.

#### 6. Portfolio & competitor monitoring

**Brokerages** watching listing churn.
**Input:** scheduled city runs. **Output:** fresh datasets per run. **Use:** detect new/removed inventory over time.

#### 7. Relocation & buyer search

**Relocation services** sourcing options for clients.
**Input:** city + filters by rooms/area/price. **Output:** matching listings with geo + metro. **Use:** curate client shortlists.

***

### 🔗 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/etagi-property-scraper').call({
  scrapeMode: 'overview',
  city: 'ekaterinburg',
  deal: 'sale',
  maxResults: 50,
});

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/etagi-property-scraper').call(
    run_input={'scrapeMode': 'overview', 'city': 'kazan', 'deal': 'rent', 'maxResults': 50}
)

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

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~etagi-property-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"scrapeMode": "overview", "city": "tyumen", "deal": "sale", "maxResults": 50}'
```

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

1. **Trigger**: Schedule or webhook
2. **HTTP Request**: Call the actor API
3. **Process**: Handle JSON results
4. **Action**: Save, notify, or transform

***

### 📊 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
- Pay-per-result: only charged for listings actually extracted
- Same clean fields, at scale

💸 **Transparent pay-per-result pricing** — no subscriptions, no wasted spend on blocked or empty runs.

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

***

### ❓ Frequently Asked Questions

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

**Q: Which cities are supported?**
A: Any city Etagi covers — pass its slug (e.g. `tyumen`, `moskva`, `kazan`). The scraper targets exactly the city you choose.

**Q: Can I get both sale and rent?**
A: Yes — toggle the `deal` field. Rent rows include deposit, rental period and online-rent flags.

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

**Q: Does it support new-builds?**
A: Yes — new-building flags, complex (ЖК) name and completion year/quarter are included.

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

***

### 🐛 Troubleshooting

**No results returned**

- Check the city slug is correct (read it from the subdomain on Etagi, e.g. `kazan.etagi.com` → `kazan`).
- Loosen any price/area/rooms filters that may be too narrow.

**Fewer results than expected**

- FREE tier caps each run at 25 listings — upgrade to PAID for unlimited.
- Raise `maxResults`.

**Detail mode returns "not found"**

- The listing id may have rotated or been delisted. Verify the URL opens on Etagi.

***

### ⚖️ 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/).

*This is an independent tool and is not affiliated with, endorsed by, or sponsored by Etagi (Этажи) or its operators. "Etagi" / "Этажи" is a trademark of its respective owner. You are responsible for complying with Etagi's terms of service and all applicable laws when using this tool.*

***

### 🤝 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** — fast, cheap, ungated. Pulls every core field straight from Etagi's listings feed (price, price/m², rooms, area, floor, building year, GPS, metro, photos, new-build complex).

🔍 **DETAIL** — refresh specific properties by their listing URL, with the full field set. Priced higher per result.

**TIP:** Start with Overview — switch to Detail only when you need to refresh exact properties by URL.

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

🧭 How to tell the scraper what to fetch. **Usually leave this blank — it is auto-inferred** from your inputs:

- **By city** — search a city + filters/sort (the default for Overview).
- **By listing URL** — Detail mode only: paste specific Etagi listing URLs to refresh those exact properties.

**NOTE:** *By listing URL* is valid only when Scrape mode = Detail.

## `city` (type: `string`):

🏙️ Which Russian city to search (Etagi's city slug). A specific city is targeted **deterministically** — the scraper resolves and pins that exact city, and refuses to return another city's data.

**Verified slugs:** `tyumen` · `moskva` (Moscow) · `sankt-peterburg` (St. Petersburg) · `ekaterinburg` · `novosibirsk` · `kazan` · `krasnodar` · `chelyabinsk` · `omsk` · `rostov-na-donu` · `samara` · `ufa` · `perm`. Other Russian cities Etagi covers also work.

**HOW TO FIND A SLUG:** open the city on Etagi and read the subdomain from the URL — e.g. `kazan.etagi.com` → `kazan`.

## `deal` (type: `string`):

🤝 Whether to scrape properties **for sale** or **for rent**.

## `objectType` (type: `string`):

🏠 Property type to search. **Flat** (apartment) is the primary, best-covered inventory; the others are available too.

## `listingUrls` (type: `array`):

🆔 **Detail mode only.** Specific Etagi listing URLs to refresh as full property records (e.g. `https://tyumen.etagi.com/realty/12938989/`).

**BULK EDIT:** Click "Bulk edit" to paste many URLs, one per line.

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

🔢 Maximum listings to extract this run.

- **FREE tier:** capped at 25 listings per run.
- **PAID tier:** unlimited — set as high as you need.

## `sort` (type: `string`):

↕️ How Etagi orders the listings before they are scraped.

## `priceMin` (type: `integer`):

💸 Optional. Minimum price filter in rubles.

## `priceMax` (type: `integer`):

💰 Optional. Maximum price filter in rubles.

## `areaMin` (type: `integer`):

📐 Optional. Minimum total area in square meters.

## `areaMax` (type: `integer`):

📐 Optional. Maximum total area in square meters.

## `rooms` (type: `integer`):

🚪 Optional. Exact number of rooms (use 0 for studio).

## `floorMin` (type: `integer`):

🛗 Optional. Minimum floor.

## `floorMax` (type: `integer`):

🛗 Optional. Maximum floor.

## `yearMin` (type: `integer`):

📅 Optional. Minimum building construction year.

## `yearMax` (type: `integer`):

📅 Optional. Maximum building construction year.

## Actor input object example

```json
{
  "scrapeMode": "overview",
  "searchMode": "byCity",
  "city": "tyumen",
  "deal": "sale",
  "objectType": "flat",
  "listingUrls": [
    "https://tyumen.etagi.com/realty/12938989/"
  ],
  "maxResults": 100,
  "sort": "default"
}
```

# Actor output Schema

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

Scraped Etagi listings (JSON/CSV/Excel).

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/etagi-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/etagi-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 '{}' |
apify call sian.agency/etagi-property-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Etagi Scraper — Russia Property Data & API",
        "description": "Etagi scraper & real estate data API for Russia's largest property-agency network. Sale & rent listings across many Russian cities: price (RUB), price/m², rooms, area, floor, building year, GPS, metro, photos, new-build complex — clean JSON/CSV.",
        "version": "1.0",
        "x-build-id": "LR2bFkGcsnqLIAA1T"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/sian.agency~etagi-property-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-sian.agency-etagi-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~etagi-property-scraper/runs": {
            "post": {
                "operationId": "runs-sync-sian.agency-etagi-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~etagi-property-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-sian.agency-etagi-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** — fast, cheap, ungated. Pulls every core field straight from Etagi's listings feed (price, price/m², rooms, area, floor, building year, GPS, metro, photos, new-build complex).\n\n🔍 **DETAIL** — refresh specific properties by their listing URL, with the full field set. Priced higher per result.\n\n**TIP:** Start with Overview — switch to Detail only when you need to refresh exact properties by URL.",
                        "default": "overview"
                    },
                    "searchMode": {
                        "title": "🧭 Search by (auto-detected)",
                        "enum": [
                            "byCity",
                            "byListingUrl"
                        ],
                        "type": "string",
                        "description": "🧭 How to tell the scraper what to fetch. **Usually leave this blank — it is auto-inferred** from your inputs:\n\n- **By city** — search a city + filters/sort (the default for Overview).\n- **By listing URL** — Detail mode only: paste specific Etagi listing URLs to refresh those exact properties.\n\n**NOTE:** *By listing URL* is valid only when Scrape mode = Detail.",
                        "default": "byCity"
                    },
                    "city": {
                        "title": "🏙️ City",
                        "type": "string",
                        "description": "🏙️ Which Russian city to search (Etagi's city slug). A specific city is targeted **deterministically** — the scraper resolves and pins that exact city, and refuses to return another city's data.\n\n**Verified slugs:** `tyumen` · `moskva` (Moscow) · `sankt-peterburg` (St. Petersburg) · `ekaterinburg` · `novosibirsk` · `kazan` · `krasnodar` · `chelyabinsk` · `omsk` · `rostov-na-donu` · `samara` · `ufa` · `perm`. Other Russian cities Etagi covers also work.\n\n**HOW TO FIND A SLUG:** open the city on Etagi and read the subdomain from the URL — e.g. `kazan.etagi.com` → `kazan`.",
                        "default": "tyumen"
                    },
                    "deal": {
                        "title": "🤝 Deal type",
                        "enum": [
                            "sale",
                            "rent"
                        ],
                        "type": "string",
                        "description": "🤝 Whether to scrape properties **for sale** or **for rent**.",
                        "default": "sale"
                    },
                    "objectType": {
                        "title": "🏠 Object type",
                        "enum": [
                            "flat",
                            "house",
                            "commercial",
                            "land",
                            "garage"
                        ],
                        "type": "string",
                        "description": "🏠 Property type to search. **Flat** (apartment) is the primary, best-covered inventory; the others are available too.",
                        "default": "flat"
                    },
                    "listingUrls": {
                        "title": "🆔 Listing URLs",
                        "type": "array",
                        "description": "🆔 **Detail mode only.** Specific Etagi listing URLs to refresh as full property records (e.g. `https://tyumen.etagi.com/realty/12938989/`).\n\n**BULK EDIT:** Click \"Bulk edit\" to paste many URLs, one per line.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "🔢 Max results",
                        "minimum": 1,
                        "type": "integer",
                        "description": "🔢 Maximum listings to extract this run.\n\n- **FREE tier:** capped at 25 listings per run.\n- **PAID tier:** unlimited — set as high as you need.",
                        "default": 100
                    },
                    "sort": {
                        "title": "↕️ Sort by",
                        "enum": [
                            "default",
                            "price_asc",
                            "price_desc",
                            "area_asc",
                            "area_desc",
                            "date_desc",
                            "price_m2_asc"
                        ],
                        "type": "string",
                        "description": "↕️ How Etagi orders the listings before they are scraped.",
                        "default": "default"
                    },
                    "priceMin": {
                        "title": "💸 Min price (RUB)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "💸 Optional. Minimum price filter in rubles."
                    },
                    "priceMax": {
                        "title": "💰 Max price (RUB)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "💰 Optional. Maximum price filter in rubles."
                    },
                    "areaMin": {
                        "title": "📐 Min area (m²)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "📐 Optional. Minimum total area in square meters."
                    },
                    "areaMax": {
                        "title": "📐 Max area (m²)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "📐 Optional. Maximum total area in square meters."
                    },
                    "rooms": {
                        "title": "🚪 Rooms",
                        "minimum": 0,
                        "type": "integer",
                        "description": "🚪 Optional. Exact number of rooms (use 0 for studio)."
                    },
                    "floorMin": {
                        "title": "🛗 Min floor",
                        "minimum": 0,
                        "type": "integer",
                        "description": "🛗 Optional. Minimum floor."
                    },
                    "floorMax": {
                        "title": "🛗 Max floor",
                        "minimum": 0,
                        "type": "integer",
                        "description": "🛗 Optional. Maximum floor."
                    },
                    "yearMin": {
                        "title": "📅 Min build year",
                        "minimum": 0,
                        "type": "integer",
                        "description": "📅 Optional. Minimum building construction year."
                    },
                    "yearMax": {
                        "title": "📅 Max build year",
                        "minimum": 0,
                        "type": "integer",
                        "description": "📅 Optional. Maximum building construction year."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
