API для разработчиков

Публичный API мониторинга объектов недвижимости. Для доступа к данным необходим бесплатный API-токен — получите его ниже за несколько секунд.

Получить API-токен

Бесплатно, без регистрации. Обязателен он для SSE-стрима (/events/stream), пакетного запроса (POST /objects/batch) и заявки на подключение застройщика (POST /pending-developers); остальные data-эндпоинты работают и без токена, но анонимные запросы ограничены общим лимитом на IP — по умолчанию 120 запросов в минуту против 600 с токеном. Оба значения — настраиваемые администратором дефолты (кэш 60 с), а не жёсткие константы, и могут измениться без предупреждения. Передавайте токен в заголовке X-API-Key, а для SSE через EventSource — query-параметром api_token.

Токен действителен до тех пор, пока активно используется. После 90 дней без обращений токен удаляется автоматически. При злоупотреблениях (нарушения rate limit) токен может быть отозван.

Базовая информация

Base URL: /api/v1

Swagger UI: /api/public/docs

OpenAPI spec: /api/public/openapi.json

Условия использования

  • Бесплатный API-токен — выдаётся мгновенно, регистрация не нужна
  • Коммерческое использование данных допустимо с соблюдением авторских прав первоисточников
  • Rate limit: по умолчанию не более 600 запросов в минуту на токен — администратор может изменить лимит в любой момент
  • SLA не гарантируется — API предоставляется «как есть»
  • Сервис не несёт ответственности за действия, совершённые на основе данных API

Sandbox — тестовая среда

Для разработки и отладки интеграции доступен sandbox — полный набор публичных эндпоинтов с случайными моковыми данными. Sandbox не обращается к базе данных и не требует авторизации, но подчиняется тому же общему лимиту на IP, что и остальной API (по умолчанию 120 запросов в минуту). SSE-стрим непрерывно генерирует случайные события каждые 3–7 секунд.

Base URL: /api/v1/sandbox

SSE-стрим: /api/v1/sandbox/events/stream

Индекс эндпоинтов: /api/v1/sandbox

Пример — объекты

curl "/api/v1/sandbox/objects?page_size=3"

# Ответ — случайные объекты каждый раз
# { "total": 142, "page": 1, "items": [...] }

Пример — SSE-стрим

curl -N "/api/v1/sandbox/events/stream"

# event: REGISTRATION_OPENED
# id: sandbox-1
# data: {"event_id":"...","developer_id":"pionier",...}

# event: OBJECT_UPDATED
# id: sandbox-2
# data: {"event_id":"...","changed_fields":"[...]",...}

Доступные sandbox-эндпоинты повторяют структуру основного API: /developers, /developers/{id}/objects, /events, /events/stream, /registration-status, /health и другие. Полный список — в индексе sandbox.

Справочник эндпоинтов

GET/developers

Список активных застройщиков с количеством объектов

Запрос

curl -H "X-API-Key: $API_TOKEN" "/api/v1/developers"

Ответ

[
  {
    "id": "ghb",
    "name": "ГХБ",
    "website": "https://ghb.by",
    "telegram_channel": "https://t.me/ghb_objects",
    "active": true,
    "registration_enabled": true,
    "objects_count": 245,
    "last_check_at": "2026-03-29T10:15:00Z"
  }
]
GET/developers/{id}/destinations

Целевые направления застройщика: Telegram-каналы, Threads-аккаунты, Viber-каналы единым списком

Запрос

curl -H "X-API-Key: $API_TOKEN" \
  "/api/v1/developers/ghb/destinations"

Ответ

[
  {
    "platform": "telegram",
    "title": "ГХБ Новостройки",
    "username": "ghb_objects",
    "url": "https://t.me/ghb_objects",
    "visibility": "public",
    "member_count": 3200
  },
  {
    "platform": "viber",
    "title": "ГХБ Viber",
    "username": null,
    "url": null,
    "visibility": "private",
    "member_count": null
  }
]
GET/developers/{id}/channels

Только Telegram-каналы застройщика. Для всех платформ разом используйте /developers/{id}/destinations

Запрос

curl -H "X-API-Key: $API_TOKEN" \
  "/api/v1/developers/ghb/channels"

Ответ

[
  {
    "id": "...",
    "title": "ГХБ Новостройки",
    "type": "public_channel",
    "visibility": "public",
    "username": "ghb_objects",
    "url": "https://t.me/ghb_objects",
    "member_count": 3200
  }
]
GET/developers/{id}/objects

Объекты застройщика с фильтрацией и пагинацией

Параметры:

  • search — по названию, external_id или адресу
  • status, object_type, object_type_slug, registration_open, building, city
  • min_price, max_price, min_area, max_area, rooms
  • sort (price_asc | price_desc | area_asc | area_desc | updated_at_desc)
  • page, page_size (макс. 100)

Запрос

curl -H "X-API-Key: $API_TOKEN" \
  "/api/v1/developers/ghb/objects?registration_open=true&sort=price_asc"

Ответ

{
  "total": 3,
  "page": 1,
  "page_size": 50,
  "items": [{ "external_id": "OBJ-101", "title": "...", ... }]
}
GET/developers/{id}/objects/{ext_id}

Один объект по его external_id

Запрос

curl -H "X-API-Key: $API_TOKEN" \
  "/api/v1/developers/ghb/objects/OBJ-101"

Ответ

{ "external_id": "OBJ-101", "title": "...", "price": "85000.00", ... }
GET/objects/{object_id}/history

Лента изменений объекта. object_id — внутренний UUID объекта (поле id в схеме объекта), а не пара developer_id/external_id

Параметры:

  • limit (1–200, по умолчанию 50)
  • before — вернуть события до этой даты (ISO datetime)
  • fields — ограничить историю списком полей через запятую

Запрос

curl -H "X-API-Key: $API_TOKEN" \
  "/api/v1/objects/3fa85f64-5717-4562-b3fc-2c963f66afa6/history"

Ответ

{
  "object_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "sources": [{ "developer_slug": "ghb", "external_id": "OBJ-101" }],
  "entries": [
    {
      "occurred_at": "...",
      "event_type": "OBJECT_UPDATED",
      "changes": [{ "field": "price", "old": "84000.00", "new": "85000.00" }]
    }
  ],
  "next_before": null
}
GET/object-types

Дерево типов объектов — источник допустимых значений object_type_slug для фильтров /objects и /developers/{id}/objects

Параметры:

  • lang — язык подписи (по умолчанию ru)

Запрос

curl "/api/v1/object-types"

Ответ

[
  {
    "slug": "apartment",
    "label": "Квартира",
    "parent_slug": null,
    "is_leaf": false,
    "children": [
      { "slug": "apartment.studio", "label": "Студия", "parent_slug": "apartment", "is_leaf": true, "children": [] }
    ]
  }
]
GET/objects

Каталог объектов сразу по всем застройщикам (архивные и тестовые исключены)

Параметры:

  • developer_id — ограничить одним застройщиком
  • search, status, object_type, object_type_slug, registration_open, building, city
  • min_price, max_price, min_area, max_area, rooms
  • sort (price_asc | price_desc | area_asc | area_desc | updated_at_desc)
  • page, page_size (макс. 100)

Запрос

curl -H "X-API-Key: $API_TOKEN" \
  "/api/v1/objects?city=Минск&rooms=2&sort=price_asc"

Ответ

{
  "total": 1842,
  "page": 1,
  "page_size": 50,
  "items": [{ "developer_id": "ghb", "external_id": "OBJ-101", ... }]
}
GET/objects/recent

Объекты, впервые обнаруженные за последние N часов

Параметры:

  • since_hours — окно в часах (1–168, по умолчанию 24)
  • те же фильтры, что у /objects, кроме object_type_slug (здесь не поддерживается)
  • sort — те же варианты, что у /objects, плюс first_seen_at_desc (значение по умолчанию)

Запрос

curl -H "X-API-Key: $API_TOKEN" "/api/v1/objects/recent?since_hours=48"

Ответ

{ "total": 17, "page": 1, "page_size": 50, "items": [...] }
GET/objects/cities

Список городов, по которым есть объекты — для фильтров

Запрос

curl -H "X-API-Key: $API_TOKEN" "/api/v1/objects/cities"

Ответ

["Барановичи", "Брест", "Витебск", "Минск"]
GET/objects/suggestions

Подсказки для поисковой строки: названия, адреса и корпуса. Есть нечёткий поиск и раскрытие сокращений (ул., кв.)

Параметры:

  • q — строка запроса (обязательна)
  • developer_id — ограничить одним застройщиком
  • limit (1–20, по умолчанию 8)

Запрос

curl -H "X-API-Key: $API_TOKEN" "/api/v1/objects/suggestions?q=маяк"

Ответ

{ "items": [{ "text": "Минск Мир, дом Маяк", "kind": "title" }] }
POST/objects/batch

Пакетный запрос объектов по парам developer_id + external_id (до 100 за раз). Токен обязателен

Параметры:

  • Тело: { "items": [{ "developer_id": "ghb", "external_id": "OBJ-101" }] }

Запрос

curl -X POST -H "X-API-Key: $API_TOKEN" -H "Content-Type: application/json" \
  -d '{"items":[{"developer_id":"ghb","external_id":"OBJ-101"}]}' \
  "/api/v1/objects/batch"

Ответ

{
  "items": [{ "developer_id": "ghb", "external_id": "OBJ-101", ... }],
  "missing": [{ "developer_id": "ghb", "external_id": "OBJ-999" }]
}
GET/developers/{id}/reviews

Отзывы о застройщике со средней оценкой

Параметры:

  • page, page_size (макс. 100)

Запрос

curl -H "X-API-Key: $API_TOKEN" "/api/v1/developers/ghb/reviews"

Ответ

{
  "total": 24,
  "rating_avg": 4.2,
  "items": [{ "id": "...", "rating": 5, "text": "...", "created_at": "..." }]
}
POST/developers/{id}/reviews

Оставить отзыв. Текст проходит автомодерацию, действует суточная квота на автора: у анонимов она минимальная, у авторизованных выше, пройденная мини-игра-проверка обнуляет счётчик

Параметры:

  • Тело: { "rating": 1..5, "text"?: "…" } — text необязателен

Запрос

curl -X POST -H "Content-Type: application/json" \
  -d '{"rating":5,"text":"Сдали дом в срок"}' \
  "/api/v1/developers/ghb/reviews"

Ответ

{ "id": "...", "rating": 5, "text": "Сдали дом в срок", "created_at": "..." }
GET/developers/{id}/stats

Публичная статистика интереса к застройщику за период. Значения ниже порога (10) не показываются — приходит null

Параметры:

  • period — период в днях (7–365, по умолчанию 30)

Запрос

curl "/api/v1/developers/ghb/stats?period=30"

Ответ

{
  "developer_slug": "ghb",
  "period_days": 30,
  "page_views": 1420,
  "object_views_top": [{ "object_external_id": "OBJ-101", "title": "...", "views": 340 }],
  "clicks_to_developer": 58,
  "events_count": 12,
  "subscribers_approx": 3200
}
GET/developers/{id}/objects/{external_id}/stats

Просмотры конкретного объекта за период. null, если просмотров меньше порога (10)

Параметры:

  • period — период в днях (7–365, по умолчанию 30)

Запрос

curl "/api/v1/developers/ghb/objects/OBJ-101/stats?period=30"

Ответ

{ "object_external_id": "OBJ-101", "period_days": 30, "views": 340 }
GET/services/{id}/stats

Просмотры карточки услуги за период. null, если просмотров меньше порога (10)

Параметры:

  • period — период в днях (7–365, по умолчанию 30)

Запрос

curl "/api/v1/services/abc123/stats?period=30"

Ответ

{ "service_id": "abc123", "period_days": 30, "views": 210 }
POST/pending-developers

Заявка на подключение застройщика. Если сайт уже есть в системе — вернёт данные существующего застройщика вместо создания заявки. Токен обязателен

Параметры:

  • Тело: { "name": "…", "website": "…", "notes"?: "…" }

Запрос

curl -X POST -H "X-API-Key: $API_TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"ЖилБылСтрой","website":"https://hwb.by"}' \
  "/api/v1/pending-developers"

Ответ

{
  "id": "...",
  "name": "ЖилБылСтрой",
  "website": "https://hwb.by",
  "notes": null,
  "status": "pending",
  "created_at": "...",
  "updated_at": "..."
}
GET/registration-status

Все объекты с открытой регистрацией прямо сейчас (кэш 30 с, токен не требуется)

Запрос

curl "/api/v1/registration-status"

Ответ

[{ "developer_id": "ghb", "external_id": "OBJ-101", "registration_url": "..." }]
GET/events

История событий мониторинга

Параметры:

  • developer_id, object_id, event_type
  • since, until (ISO datetime)
  • limit (макс. 500), page

Запрос

curl -H "X-API-Key: $API_TOKEN" \
  "/api/v1/events?developer_id=ghb&event_type=REGISTRATION_OPENED&limit=10"

Ответ

{
  "total": 42,
  "items": [{ "event_type": "REGISTRATION_OPENED", "occurred_at": "...", ... }]
}
GET/events/stream

SSE-стрим событий в реальном времени

Параметры:

  • developer_id — фильтр по застройщику
  • event_types — через запятую (REGISTRATION_OPENED,...)
  • api_token — токен query-параметром (для EventSource)
  • Last-Event-ID — восстановление пропущенных событий

Запрос

curl -N -H "X-API-Key: $API_TOKEN" \
  "/api/v1/events/stream?developer_id=ghb&event_types=REGISTRATION_OPENED"

Ответ

event: REGISTRATION_OPENED
id: 1711234567890-0
data: {"external_id":"OBJ-101",...}

: keepalive
GET/field-configs

Метаданные публичных полей объекта: подписи и шаблоны текстов для событий появления/удаления/изменения поля. Кэш 5 минут

Запрос

curl "/api/v1/field-configs"

Ответ

[
  {
    "field_name": "price",
    "alias": "Цена",
    "description": null,
    "value_kind": "money",
    "empty_policy": "hide",
    "public_value_visibility": "visible",
    "appeared_template": "...",
    "removed_template": "...",
    "changed_template": "...",
    "updated_at": "..."
  }
]
GET/health

Статус сервиса и парсеров (токен не требуется)

Запрос

curl "/api/v1/health"

Ответ

{ "status": "ok", "version": "1.0.0", "developers": [...] }

SSE-стрим (Server-Sent Events)

Стрим позволяет получать события в реальном времени без постоянного опроса. Соединение остаётся открытым; сервер отправляет keepalive-пинги каждые 15 секунд. При разрыве браузер автоматически переподключается с заголовком Last-Event-ID, и сервер отдаёт все пропущенные события из буфера.

bash

# curl — события регистрации от застройщика ghb
curl -N -H "X-API-Key: $API_TOKEN" \
  "/api/v1/events/stream?developer_id=ghb&event_types=REGISTRATION_OPENED"

# С восстановлением пропущенных (Last-Event-ID)
curl -N -H "X-API-Key: $API_TOKEN" -H "Last-Event-ID: 1711234567000-0" \
  "/api/v1/events/stream?developer_id=ghb"

python

import httpx
import asyncio

async def stream_events():
    async with httpx.AsyncClient() as client:
        async with client.stream(
            "GET",
            "/api/v1/events/stream",
            headers={"X-API-Key": "sh_ваш_токен"},
            params={"developer_id": "ghb", "event_types": "REGISTRATION_OPENED"},
            timeout=None,
        ) as r:
            async for line in r.aiter_lines():
                if line.startswith("data:"):
                    import json
                    data = json.loads(line[5:].strip())
                    print(data)

asyncio.run(stream_events())

javascript

// Браузер или Node.js (EventSource API)
// EventSource не поддерживает заголовки —
// токен передаётся query-параметром api_token
const es = new EventSource(
  "/api/v1/events/stream?developer_id=ghb&api_token=sh_ваш_токен"
);

es.addEventListener("REGISTRATION_OPENED", (e) => {
  const data = JSON.parse(e.data);
  console.log("Открылась регистрация:", data.external_id);
});

es.onerror = () => {
  // Браузер автоматически переподключается
  console.log("Переподключение...");
};

go

package main

import (
  "bufio"
  "fmt"
  "net/http"
  "os"
  "strings"
)

func main() {
  req, _ := http.NewRequest("GET",
    "/api/v1/events/stream?developer_id=ghb", nil)
  req.Header.Set("X-API-Key", os.Getenv("API_TOKEN"))
  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  scanner := bufio.NewScanner(resp.Body)
  for scanner.Scan() {
    line := scanner.Text()
    if strings.HasPrefix(line, "data:") {
      fmt.Println(strings.TrimPrefix(line, "data: "))
    }
  }
}

Схема данных объекта

ПолеТипОписание
idstringUUID объекта в stroi.homes
developer_idstringСлаг застройщика (например, ghb)
external_idstringУникальный ID объекта у застройщика
titlestringНазвание объекта
object_typeenumapartment | apartments | commercial | parking | storage
statusenumfor_sale | booked | sold | removed | rent
object_urlstringСсылка на объект на сайте застройщика
registration_openbooleanОткрыта ли онлайн-регистрация
registration_urlstring?Ссылка на форму регистрации
pricedecimal?Цена в белорусских рублях
price_per_sqmdecimal?Цена за м²
estimated_pricedecimal?Расчётная цена (area × price_per_sqm). Заполняется только когда price отсутствует
areadecimal?Площадь в м²
roomsint?Количество комнат (0 = студия)
floorint?Этаж
total_floorsint?Этажность дома
buildingstring?Корпус / секция
countrystring?Страна
regionstring?Область
districtstring?Район
citystring?Город
addressstring?Полный адрес строкой, как его отдаёт источник
streetstring?Улица — разобранная часть адреса. Может быть заполнена одновременно с address
housestring?Номер дома — разобранная часть адреса
quarterstring?Квартал / микрорайон — разобранная часть адреса
completion_datedate?Срок сдачи дома
sales_start_datedate?Дата старта продаж
registration_start_datedatetime?Дата и время старта онлайн-регистрации
offline_booking_datedate?Дата старта офлайн-бронирования
image_urlstring?Изображение объекта
promotionsarray?Акции застройщика
extraobject?Дополнительные поля конкретного застройщика. Состав не фиксирован — не полагайтесь на него в интеграции
first_seen_atdatetimeДата первого обнаружения
updated_atdatetimeДата последнего обновления

Поля перечислены полностью. Машиночитаемая версия схемы — в OpenAPI-спецификации.

Changelog API

ВерсияДатаИзменения
v1.4.02026-08-03Поле estimated_price в объекте (area × price_per_sqm, когда застройщик не публикует итоговую цену). Задокументированы сквозной каталог /objects, /objects/recent, /objects/cities, /objects/suggestions, POST /objects/batch и отзывы застройщика. Уточнено: токен обязателен только для /events/stream и POST /objects/batch
v1.3.02026-06-12GET /developers/{id}/destinations — целевые направления застройщика (Telegram, Threads, Viber) единым списком
v1.2.02026-06-04Обязательные API-токены для data-эндпоинтов (X-API-Key / Bearer / ?api_token=). Бесплатная выдача через POST /api/v1/developer-tokens. Per-token rate limit 600 req/мин, авто-отзыв за злоупотребления, удаление после 90 дней неактивности. /health и /registration-status — без токена
v1.1.02026-04-18Sandbox API (/api/v1/sandbox/*) — тестовая среда с моковыми данными и SSE-стримом для разработки интеграций
v1.0.02026-03-29Первый публичный релиз: /developers, /objects, /events, /events/stream, /registration-status, /health

Политика: минорные изменения (новые поля) — обратно совместимы. Мажорная смена версии — через новый префикс /api/v2/.