API DomXML

Машиночитаемая схема: /api/v1/openapi.json (OpenAPI 3.1), интерактивный справочник — /api-reference.

REST API для управления шахматкой: жилые комплексы, квартиры, статусы, фиды. База: https://domxml.ru/api/v1. Для нейросетей есть MCP-сервер с теми же возможностями. Обзор возможностей и сценарии — на странице «API и MCP».

Быстрый старт

  1. Создайте ключ: аватарка → API и MCP → «Создать ключ», уровень editor. Скопируйте секрет — он показывается один раз.
  2. Найдите ID ЖК:
    curl https://domxml.ru/api/v1/complexes \
      -H "Authorization: Bearer dxk_ВАШ_КЛЮЧ"
    # [{"id": 1234567, "name": "Приречный", "kind": "residential", …}]
  3. Получите объекты ЖК — например, свободные двухкомнатные:
    curl "https://domxml.ru/api/v1/complexes/1234567/apartments?rooms=2&status=available" \
      -H "Authorization: Bearer dxk_ВАШ_КЛЮЧ"
    # [{"id": 345, "number": "32", "floor": 5, "price": 7810000, "status": "available", …}]
  4. Поменяйте цену:
    curl -X PUT https://domxml.ru/api/v1/complexes/1234567/apartments/345 \
      -H "Authorization: Bearer dxk_ВАШ_КЛЮЧ" \
      -H "Content-Type: application/json" \
      -d '{"price": 7950000}'

Правка сразу видна в панели и на витрине и попадает в журнал ЖК со способом key. Фиды пересобираются сами раз в 3 часа, если в ЖК были изменения; POST …/feeds/{feed}/generate — чтобы пересобрать сейчас.

Аутентификация

Создайте ключ в панели: аватарка → API и MCP → «Создать ключ». Секрет показывается один раз. Передавайте его в заголовке:

curl https://domxml.ru/api/v1/complexes \
  -H "Authorization: Bearer dxk_ВАШ_КЛЮЧ"

При создании ключа выбираются:

Ключом закрыто всегда — только в панели, ответ 403: профиль и вход (/auth), выпуск ключей (/apikeys) и подключений нейросетей (/oauth), обращения в поддержку (/support), уведомления (/notifications), партнёрская программа (/partner), управление доступами к ЖК (любой путь с /access), подключение Битрикс24 (/b24). Каналы публикации — только с отдельным разрешением ключа, а удаляются только в панели (ниже).

Основные эндпоинты

Проекты (ЖК, посёлки, паркинги…), застройщик, корпуса

МетодПутьОписание
GET/complexesСписок проектов: свои и те, к которым вам открыли доступ. Вид — поле kind (residential, settlement, parking, commercial, house, resale — виды проектов), площадки фидов, доступные виду, — feedPlatforms
POST/complexesСоздать проект: обязательно name; kind — вид проекта (по умолчанию residential); developer — застройщик: {"name": "…"} — новый, {"fromComplexId": N} — синхронизированный с застройщиком проекта N. Вместе с проектом одной транзакцией создаются застройщик и, только у ЖК, три вида из окон (подробнее)
GET/complexes/{id}Данные ЖК
PUT/complexes/{id}Изменить проект (частичное тело). Смена kind проверяется: если в проекте есть то, чего у нового вида не бывает, — 422 (ниже)
DELETE/complexes/{id}Удалить ЖК в корзину на 7 дней (уровень full, только владелец ЖК); POST /complexes/{id}/restore — вернуть
GET, PUT/complexes/{id}/developerЗастройщик: название, ИНН, ОГРН, сайт, телефон, логотип
GET/developersЗастройщики ваших проектов — выбрать «из ваших» при создании нового (подробнее)
GET/complexes/{id}/readinessЧек-лист «Что сделать для работы»: реквизиты, контакты, фото, объекты, фид, витрина (подробнее)
GET, POST/complexes/{id}/buildingsКорпуса, очереди посёлка, здания паркинга и коммерции; создать — обязательно name. Назначение purpose (residential, commercial, parking, phase) по умолчанию — по виду проекта; неподходящее виду — 422. У отдельного дома зданий нет
GET, PUT, DELETE/complexes/{id}/buildings/{bid}Корпус. Удалить можно только пустой
GET, POST/complexes/{id}/window-viewsВиды из окон ЖК; …/window-views/domclick-values — допустимые значения Домклика
PUT, DELETE/complexes/{id}/window-views/{vid}Изменить или удалить вид
GET, POST/complexes/{id}/discountsАкции; …/discounts/types — типы акций
PUT, DELETE/complexes/{id}/discounts/{did}Изменить или удалить акцию. Скидка на жильё: value + valueUnit (percent или rub) и target — где действует: info (только описание, цены не меняет; по умолчанию), all, filter (buildings, kinds, rooms, areaMin, areaMax), objects (ids). Цена со скидкой уходит в фиды Домклика, Яндекса, Авито, VK и на витрину (discountPrice в снимке); в Циан — cianActionId из его кабинета
POST/complexes/{id}/discounts/{did}/objectsДобавить (add) или убрать (remove) объекты акции — режим «выбранные объекты»
GET/dictionariesДопустимые значения справочных полей: отделка, класс, тип дома, состояние корпуса, статусы, вид проекта (complex.kind), тип гаража (apartment.garageType); complex.kindRules — правила видов проекта

Квартиры

МетодПутьОписание
GET/complexes/{id}/apartmentsВсе объекты ЖК со всеми полями, включая internalId; поле crmBooking — активная бронь клиента CRM. Фильтры: kind (вид объекта), rooms, floor, status, min_price, max_price, min_area, max_area (общая площадь). Ответ — массив целиком, без пагинации
GET/complexes/{id}/apartments/deltaЧто изменилось с ревизии since — в том же виде, что список: {"rev", "fullRequired": false, "updated": […], "removed": [ID]}. В removed — удалённые и снятые с публикации объекты. Если журнал ревизию уже не помнит — "fullRequired": true: загрузите список целиком. Текущую ревизию даёт /version
POST/complexes/{id}/apartmentsСоздать квартиру. complexId в теле не нужен — берётся из пути. Нужно хотя бы одно из полей number, floor, rooms, areaTotal, price, иначе 422
POST/complexes/{id}/apartments/bulkСоздать до 500 квартир одним запросом: {"apartments": [{…}, …]}. Всё или ничего: при ошибке в любой квартире не создаётся ни одна
GET/complexes/{id}/apartments/{aid}Одна квартира
PUT/complexes/{id}/apartments/{aid}Изменить квартиру (частичное тело)
DELETE/complexes/{id}/apartments/{aid}Удалить объект (уровень full). Куплен клиентом CRM — 409; активная бронь — 409 с crmBooking, повтор с ?force=true снимает бронь и удаляет
PUT/complexes/{id}/apartments/bulkМассовое изменение: {"apartmentIds": […], "updates": {…}}, до 500 квартир
GET/complexes/{id}/apartments/statusesСтатусы квартир: базовые available, reserved, sold (system: true) и свои статусы застройщика
GET/complexes/{id}/changelogЖурнал ЖК: кто, когда, было и стало и способ (via: panel, key — ключ или подключение нейросети по REST, mcp, excel, feed, crm, support, b24; none — старые записи без пометки). Параметры: entityType (apartment, complex, developer, building, discount, window_view, status), action, days — за сколько дней, userId, via, apartmentId — история объекта, limit (по умолчанию 100, до 500) и offset. Новые записи первыми. Автор — userName и userPublicId, почта не отдаётся. Хранится год. …/changelog/stats?days=30 — сводка по действиям, сущностям и авторам

Фото и планировки

МетодПутьОписание
POST/apartment-images/uploadЗагрузить файл: multipart с полями image (файл), complex_id, необязательно apartment_id и image_type (photo | floorplan). Одинаковые файлы не дублируются
POST/apartment-images/bulk-addПривязать загруженные файлы к квартирам: apartmentIds, imageFileIds, imageType
GET/apartment-images/apartment/{aid}Фото и планировки квартиры

Уже загруженные файлы можно привязать и при создании квартиры: поля imageIds и floorPlanIds.

Любую загруженную картинку сервер пережимает сам: не больше 1920 пикселей по большей стороне, JPEG с качеством 85, поворот по EXIF, прозрачный фон — белым, метаданные (в том числе координаты съёмки) удаляются. Исходник — JPEG, PNG или WebP до 40 МБ; повреждённый файл отклоняется с ошибкой 400.

Планировка квартиры — поле floorplanUrl, а если оно пустое, первая привязанная планировка (imageType: "floorplan"). Так её читают снимок (floorPlan), фиды и проверка фида, поэтому заполнять floorplanUrl после bulk-add не нужно.

Ссылка на страницу квартиры для фидов VK Рекламы и Яндекс Директа — поле pageUrl: полный адрес http(s)://… на вашем сайте, до 500 символов. Его берут фиды, где включён «Ваш сайт» (adLinks ЖК), а где его нет — шаблон; пусто (null или "") — снять. В Excel — колонка «Ссылка на страницу» (BF), пустая ячейка ссылку не снимает.

Фиды и импорт

МетодПутьОписание
GET/complexes/{id}/feedsФиды ЖК: площадка, отбор (selection: all | filter | manual), постоянная ссылка url, counts — сколько объектов попадёт и почему не попали остальные, missing — без чего площадка отклонит фид, overlaps — общие объекты с другими фидами той же площадки, последний выпуск. У площадки может быть несколько фидов (Домклик — один на ЖК), до 20 на ЖК. platforms — площадки, доступные виду проекта
POST/complexes/{id}/feedsСоздать фид: {platform, title?, selection, filter?, apartmentIds?, premises?, adLinks?, complexData?}. filter — kinds, buildingIds, rooms (studio, 1, 2, 3, 4+), priceFrom/To, areaFrom/To, floorFrom/To; manual — только apartmentIds, новые объекты сами не попадают. Фид «все объекты» получает стандартный адрес complex_{id}.xml, если у площадки ЖК ещё нет стандартного фида (выключенный тоже занимает адрес, удаление освобождает); остальные — {площадка}/{код}.xml. complexData — данные ЖК, которые нужны площадке: ID ЖК в её справочнике (yandexBuildingId, cianJkId, avitoDevelopmentId; у посёлка — yandexVillageId, cianKpId) и шаблон адреса страницы объекта objectUrlTemplate для VK и Директа. Пишутся в сам ЖК вместе с фидом (ошибка фида — не пишутся) и общие для всех его фидов; в ответе — complexData после записи. Имена полей — camelCase или snake_case. Собирается сразу — итог в build. Площадка, недоступная виду проекта, — 422 со списком доступных в ctx.allowed
POST/complexes/{id}/feeds/previewСколько объектов попадёт — до сохранения (тело как у создания, ?feedId= — правка существующего). complexData учитывается в расчёте, но не записывается
GET, PATCH, DELETE/complexes/{id}/feeds/{feed}Фид, правка (не присланные поля не меняются, isActive: false — выключить, файл удаляется), удаление. {feed} — ID фида или площадка: тогда её стандартный фид
GET/complexes/{id}/feeds/{feed}/validate, …/logs, …/downloadГотовность фида, история выпусков, скачать файл
GET/complexes/{id}/feeds/statusСводка по стандартным фидам площадок (старый формат)
GET/complexes/{id}/feeds/validateПроверка готовности: feeds.{площадка} — blocking (фид не соберётся), recommended (стоит поправить), count (объектов в фиде) для всех шести площадок, включённых и нет; errors/warnings — сводно по включённым
PUT/complexes/{id}/feeds/{type}/toggleВключить или выключить стандартный фид площадки: {"enabled": true} (устаревшее — используйте POST/PATCH …/feeds). Включение не собирает фид сразу — соберёт планировщик или …/generate; PATCH …/feeds/{feed} с isActive: true собирает сразу
GET/complexes/{id}/feeds/object-linksСсылки рекламных фидов: опубликованные витрины с этим ЖК, шаблон, сколько объектов со своей ссылкой; по vk и direct — настройка и счётчики (stats: в продаже, попадёт в фид, по своей ссылке, по шаблону, на витрину, без ссылки, на другом домене, без фото). Настройка ссылок — у каждого фида VK и Директа своя: adLinks в PATCH …/feeds/{feed} ({"site": true, "showcase": false, "showcaseId": 12}, null — по данным ЖК); здесь — настройка стандартного фида площадки. VK принимает ссылки одного домена — у него включается что-то одно
POST/complexes/{id}/feeds/{feed}/generateПересобрать фид: ID фида или площадка (domclick | cian | yandex | avito | vk | direct) — её стандартный фид. Фид должен быть включён, иначе 409; несуществующий ID — 404
GET/filesФайловое хранилище: картинки и документы с местами использования. category: all | realty (объекты недвижимости) | crm (витрины, виджеты) | unused | system (вложения поддержки: system: true, их id — ID вложения, не файла хранилища, переименовать и удалить нельзя); kind, complexId, q. Ключу, ограниченному списком ЖК, недоступно
POST/filesЗагрузить (multipart file, title): картинка сжимается, документ — PDF, Excel, Word, CSV, TXT, XML до 25 МБ, только владельцу. 413 — закончилось место. GET /files/usage — занято и лимит
GET, PATCH, DELETE/files/{id}, /files/{id}/contentФайл, переименование {title}, удаление (используемый — 409 со списком мест, ?force=true — убрать из мест и удалить), скачивание документа
GET/complexes/{id}/filesДля форм ЖК: картинки этого ЖК и файлы хранилища; привязать — imageFileId в imageIds объекта, POST /apartment-images/bulk-add или POST /apartment-images/complex/{id}/link (фото ЖК)
GET/import-export/templateШаблон Excel для импорта шахматки; ?complex_id=N — шаблон под этот проект (подробнее)
POST/import-export/import/preview, …/executeИмпорт Excel — файл .xlsx (листы «Застройщик», «ЖК», «Корпуса», «Квартиры»; корпус из колонки «Корпус», которого нет в ЖК, создаётся сам): сначала предпросмотр — ошибки и что изменится у каждого объекта (changes: было → стало), затем применение. Предпросмотр без ошибок отдаёт importId — запись по нему идёт в фоне (/import-export/jobs/{id}/execute), файл второй раз не нужен; …/execute с файлом пишет сразу. В warnings — странные значения (этаж выше этажности, координаты вне России, цена за м²). Строки без изменений не трогаются; изменения пишутся в журнал ЖК и расходятся по синхронизированным ЖК, фиды помечаются к пересборке. Права: владелец, администратор или редактор с правом «Импорт»
POST/import-export/feed/previewИмпорт из фида площадки по ссылке ({url, format}, формат domclick, yandex, cian или avito) — разовый, не синхронизация. Сервер скачивает и разбирает фид и показывает тот же предпросмотр, что у Excel, плюс importId и feed: ЖК фида, куда они пойдут, сколько картинок скачается. Не больше 20 проверок в час
POST/import-export/feed/{id}/retargetСменить, куда импортировать ЖК фида ({targets: [ID ЖК или null]}) — пересчёт без повторного скачивания
POST/import-export/jobs/{id}/executeЗапустить импорт по importId из предпросмотра (фид или Excel без ошибок): фоновая задача скачивает и сжимает картинки фида, пишет данные (журнал — способ feed, excel или mcp). Ход и итог — GET /import-export/jobs/{id}
GET/import-export/exportВыгрузка шахматки в Excel: ЖК с правом «Выгрузка» (у владельца и администратора — всегда). complex_ids — через запятую, до 200 за раз; ЖК без права — 403, чужой или несуществующий — 404

Яндекс, Циан и Авито получают квартиры как новостройку от застройщика. Квартиры без цены или общей площади в эти три фида не попадают.

Фиды для рекламы. vk — каталог недвижимости VK Рекламы (Центр коммерции, собственный формат VK), direct — фид недвижимости Яндекс Директа для товарных объявлений ЕПК и товарных кампаний. В них попадают свободные квартиры со ссылкой на свою страницу (для VK — ещё и с планировкой или фото), а ЖК — отдельной позицией или каталогом. Ссылка берётся из шаблона objectUrlTemplate у ЖК (например, https://site.ru/flats/{number}; подстановки {number}, {id}, {building}), а если он пуст — со страницы квартиры на опубликованной витрине. Без ссылок, города (и для VK — региона и адреса), а для Директа — без названия застройщика фид не собирается: ответ 400 со списком.

Виды проектов

Проект — это ЖК, коттеджный посёлок, паркинг, бизнес-центр, отдельный дом или вторичка агентства. Вид задаёт поле kind проекта: от него зависят объекты, которые в нём заводятся, назначения зданий и площадки фидов.

kindЧто внутриЗданияПлощадки фидов
residential — жилой комплексквартиры и апартаменты (flat), коммерция, машиноместа, кладовыекорпуса: residential, commercial, parkingвсе шесть: Домклик, Яндекс Недвижимость, Циан, Авито, VK Реклама, Яндекс Директ
settlement — коттеджный посёлокучастки, дома, таунхаусы, коммерцияочереди (phase) и любые другиевсе, кроме Домклика
parking — паркинг и гаражимашиноместа, гаражи (garage), кладовыетолько parkingVK Реклама и Яндекс Директ
commercial — коммерческая недвижимостьпомещения и машиноместаcommercial, parkingVK Реклама и Яндекс Директ
house — отдельный домодин дом с участком (house)нетЯндекс Недвижимость, Циан, Авито, Яндекс Директ
resale — вторичка агентства или частного риэлтораквартиры, комнаты (room), дома, таунхаусы, участки, гаражи, машиноместа, кладовые, коммерция — у каждого свой адреснетЯндекс Недвижимость (эту же ссылку берут Домклик и Move), Циан, Авито, VK Реклама, Яндекс Директ

Паркинг и коммерция внутри ЖК остаются в ЖК — зданиями с назначением parking или commercial — и уходят на все площадки, кроме Домклика.

Новый проект: застройщик, готовность, шаблон Excel

Те же ручки, что у мастера «Добавить» в панели: проект с застройщиком — одним запросом, затем объекты из Excel по шаблону проекта и чек-лист готовности.

curl -X POST https://domxml.ru/api/v1/complexes \
  -H "Authorization: Bearer dxk_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"name": "Паркинг на Ленина", "kind": "parking", "city": "Казань",
       "developer": {"name": "ООО «СЗ Восток»"}}'
# 201 {"id": 1234590, "kind": "parking", "feedPlatforms": ["vk", "direct"], …}

Виды объектов, гаражи и посёлки

Квартиры, коммерция, машиноместа, кладовые, гаражи, участки и дома — объекты одного списка /complexes/{id}/apartments. Вид задаёт поле kind, по умолчанию flat. Какие виды можно завести, зависит от вида проекта (kind у самого проекта):

ПроектВиды объектов
residential — жилой комплексflat — квартира, commercial — коммерческое помещение, parking — машиноместо, storage — кладовая
settlement — коттеджный посёлокplot — участок, house — дом с участком, townhouse — таунхаус, commercial
parking — паркинг и гаражиparking, garage — гараж, storage
commercial — коммерческая недвижимостьcommercial, parking
house — отдельный домодин house
resale — вторичкаflat, room — комната, house, townhouse, plot, garage, parking, storage, commercial

Вид, который не подходит проекту, отклоняется с 422. Отобрать объекты одного вида — GET …/apartments?kind=parking. Справочные поля принимают код или подпись из GET /dictionaries.

МетодПутьОписание
GET, POST/complexes/{id}/house-projectsКаталог проектов домов посёлка: name, area, floors, bedrooms, bathrooms, wallMaterial, width, length, minLandArea — минимальный участок, buildMonths, description, prices — цена по вариантам готовности {"box", "warm", "whitebox", "turnkey"}, images — до 50 картинок ({"url", "type": "render" | "plan"}), isActive, sortOrder
GET, PUT, DELETE/complexes/{id}/house-projects/{pid}Проект, правка, удаление

Что уходит в фиды. Квартиры попадают во все фиды. Участки, дома и таунхаусы — во все, кроме Домклика. Нежилое — только туда, где оно отмечено у фида (premises в POST/PATCH …/feeds) и где площадка его принимает: Яндекс и Авито — коммерция и машиноместа, Циан — коммерция, машиноместа и кладовые, VK — коммерция, машиноместа, кладовые и гаражи, Директ — машиноместа и гаражи. Какие площадки вообще доступны проекту — по его виду (выше). Прежнее поле ЖК premisesFeeds ({"yandex": ["commercial", "parking"]}) по-прежнему принимается и меняет стандартные фиды площадок; для новых интеграций используйте premises у фида.

В снимке и дельтах у объекта есть kind, у участков, домов и таунхаусов — ещё landArea, street, saleMode, houseStage, planShape (в профиле full — и остальные поля посёлка), а у ЖК-посёлка — блок complex.settlement: генплан, шоссе, значения по умолчанию и каталог проектов домов. У объектов вторички — address, city, district, lat, lon, в профиле full — ещё метро, дом, ремонт, сделка, комнаты и agent (имя и рабочий телефон ответственного, как в объявлениях); номера квартиры в снимке нет.

Поля и типы

Имена полей принимаются и в camelCase (areaTotal), и в snake_case (area_total). Отсутствующее поле не меняется, null очищает значение.

Одно поле в разных местах

REST управляет данными, снимок — публичный контракт для сайтов с короткими именами и своей версией (contract), инструменты MCP принимают аргументы в snake_case.

RESTСнимок и дельтыMCP
areaTotalareaarea_total
pricePerMeterpricePerM2 — если не задана, считается как цена / площадь—
акции ЖК (/discounts)discountPrice, discountTitle — цена по действующей акции и её название; price — без скидки. В complex.discounts — только идущие сегодня, с датой until—
entrancesectionentrance
building, buildingIdbuilding, buildingIdbuilding
rooms, isStudio, euroPlanrooms, roomsKindrooms
floorplanUrlfloorPlan (профиль full)—
internalIdне публикуется—

roomsKind — вид планировки одной строкой: studio — студия, euro2, euro3… — евроформат (euroPlan: true, цифра — значение rooms), 1, 2, 3… — классическая, число комнат.

internalId в снимок не попадает: снимок же отдаёт публичный канал витрины, а внутренние номера наружу не уходят. Для сопоставления храните id квартиры DomXML или берите internalId из GET /complexes/{id}/apartments.

В снимке у каждого корпуса (complex.buildings) есть completionYear и completionQuarter — срок сдачи корпуса или ЖК.

Синхронизация шахматки: версия, снимок, изменения

Чтобы держать шахматку на своём сайте в актуальном состоянии, не нужно скачивать её целиком. Сначала спросите версию — это одна строка из базы, — и качайте данные, только если она изменилась.

МетодПутьОписание
GET/complexes/{id}/versionВерсия ЖК: rev, время изменения, счётчики по статусам, ссылка на снимок
GET/complexes/{id}/snapshotСнимок целиком: profile=short|full, rev=N
GET/complexes/{id}/changesЧто изменилось: since=N, profile=short|full — изменённые (items) и удалённые (deleted) лоты в формате снимка

Версия ЖК растёт при любом изменении, которое видно покупателю: цена, статус, площадь, фотографии, корпуса, акции, данные самого ЖК. Служебные правки её не двигают.

# 1. дёшево узнаём, изменилось ли что-нибудь
curl -H "Authorization: Bearer dxk_КЛЮЧ" \
  https://domxml.ru/api/v1/complexes/1234567/version
# {"rev": 42, "changedAt": "...", "apartments": {"available": 180, "total": 344},
#  "snapshotUrl": "/api/v1/complexes/1234567/snapshot?rev=42"}

# 2. если rev вырос — забираем только изменения
curl -H "Authorization: Bearer dxk_КЛЮЧ" \
  "https://domxml.ru/api/v1/complexes/1234567/changes?since=41"

# 3. или снимок целиком: адрес с rev неизменяем, его можно кэшировать навсегда
curl -H "Authorization: Bearer dxk_КЛЮЧ" \
  "https://domxml.ru/api/v1/complexes/1234567/snapshot?rev=42"

Надёжнее всего сверять rev из /version с сохранённым у себя: совпал — ничего не качать. Адрес snapshotUrl с ревизией неизменяем, его можно кэшировать навсегда. Снимок отдаётся и с заголовком ETag (если ответ пришёл сжатым, nginx помечает его как слабый: W/"…") — его можно вернуть в If-None-Match как есть.

complexChanged: true в ответе /changes значит, что менялись данные самого ЖК — например, описание, корпуса или акции. Их в дельте нет: перечитайте блок complex из снимка. Изменения объектов при этом приходят как обычно, в items и deleted.

Дельта с profile=full отдаёт квартиры в том же виде, что снимок, вместе с images и floorPlan.

Журнал изменений хранится 30 дней и минимум 50 ревизий. Если запрошенная версия уже забыта, ответ придёт с "fullRequired": true — значит, нужно перекачать снимок целиком.

Публичное API виджета и витрины

Этот раздел — для кода, который работает в браузере посетителя: сам виджет, витрина или ваш скрипт на сайте. Авторизации нет, вместо неё — ключ канала dxp_, который создаётся в панели вместе с виджетом или витриной. Ключ виден в исходном коде страницы и секретом не является: доступ ограничивают список разрешённых доменов и лимиты запросов.

МетодПутьОписание
GET/api/public/v1/{ключ}/versionВерсия канала и счётчики по каждому ЖК
GET/api/public/v1/{ключ}/apartmentsСнимок канала: profile=short|full, v=версия
GET/api/public/v1/{ключ}/changesИзменения: since=8 или since=1234567:8,1234568:3
POST/api/public/v1/{ключ}/leadsЗаявка из формы — сразу клиентом в CRM
fetch('https://domxml.ru/api/public/v1/dxp_КЛЮЧ/version')
  .then(r => r.json())
  .then(v => fetch(`https://domxml.ru/api/public/v1/dxp_КЛЮЧ/apartments?v=${v.version}`))
  .then(r => r.json())
  .then(data => console.log(data.complexes[0].apartments.length));

Ограничения: 240 запросов в минуту с одного адреса и 1200 в минуту на канал, сверх — 429. Если канал выключен или удалён, ответ — 404: по ключу нельзя узнать, что витрина существует, но скрыта.

Домены. Если у канала задан список доменов, запрос должен прийти с одного из них: сервер смотрит заголовок Origin, а без него — Referer. Браузер присылает их сам, а запрос без обоих заголовков — curl или ваш сервер — получит 403 «Этот виджет не разрешён на текущем домене». Для проверки из терминала передайте заголовок явно:

curl https://domxml.ru/api/public/v1/dxp_КЛЮЧ/version \
  -H "Origin: https://ваш-сайт.ru"

Канал с пустым списком доменов отвечает любому сайту и запросам без заголовков. Серверу, который синхронизирует шахматку, удобнее REST API с ключом dxk_ (выше): там проверки домена нет.

Заявка с сайта

Форма на вашей странице может отправлять заявку тем же ключом — она попадёт в CRM как клиент со статусом по умолчанию и источником «Виджет». Обязательны имя и телефон; всё остальное по желанию.

fetch('https://domxml.ru/api/public/v1/dxp_КЛЮЧ/leads', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'Пётр',
    phone: '+7 917 000-11-22',
    apartmentId: 96,             // из снимка, необязательно
    comment: 'Перезвоните после 18',
    utm: { utm_source: 'yandex' },
    ft: Date.now() - formOpenedAt, // сколько форма была открыта, мс
    company: ''                  // ловушка для ботов: поле должно остаться пустым
  })
}).then(r => r.json());

Ответ — {"ok": true}. Он одинаков и для новой карточки, и когда человек уже писал с этого телефона: во втором случае заявка ложится записью в его карточку, а не создаёт дубль. По ответу нельзя проверить, есть ли телефон в вашей базе.

Два поля нужны против ботов. company прячут от человека стилями — если оно заполнено, заявка тихо отбрасывается. ft — сколько миллисекунд форма была открыта: меньше полутора секунд считается автоматической отправкой. В обоих случаях ответ тот же {"ok": true}, чтобы по нему нельзя было подобрать обход. Лимиты: 10 заявок в час с одного адреса и 5 в сутки с одного телефона, дальше — 429.

Если в настройках канала включена галочка согласия, передавайте consent: true — иначе придёт 400. Вместе с заявкой сохраняются метки рекламы, адрес страницы и текст согласия, который видел посетитель.

Каналы публикации

Виджеты и витрины создаются в панели, но ими же можно управлять по API — например, завести по виджету на каждый ЖК скриптом. Канал принадлежит проекту CRM: собирается из его ЖК, заявки с него приходят в его CRM.

МетодПутьОписание
GET/channels?crm={id}Каналы проекта CRM с кодом вставки, сам проект (crm: publicId, name, canPublish) и его ЖК (complexes). Без crm — первый проект, где есть право «Настройка витрины»
POST/channels?crm={id}Создать: kind (widget | showcase), complexIds — только ЖК этого проекта, template
GET/channels/{id}Канал целиком: настройки, ЖК, домены, статус
PATCH/channels/{id}Настройки, оформление, блоки, домены, состав ЖК — всё сразу
PATCH/channels/{id}/designТолько оформление: accent, mode, radius
PATCH/channels/{id}/blocksТолько блоки витрины, включая квиз
PATCH/channels/{id}/formТолько форма заявки: поля, тексты, согласие
PATCH/channels/{id}/quizКвиз на витрине: quizId — квиз кнопки и адреса /quiz, floatingQuizId — плавающий чат, on, title — подпись кнопки (квизы)
PATCH/channels/{id}/domainsТолько список доменов, где разрешена вставка
GET/channels/schemaДопустимые виды, пресеты, блоки и значения настроек
GET/channels/{id}/embedКод вставки и ссылки: предпросмотр, витрина
GET/channels/{id}/statsПоказы, заявки и конверсия за 30 дней
GET/channels/{id}/logКто, когда и через что менял канал
POST/channels/{id}/publishОпубликовать
POST/channels/{id}/unpublishСнять с публикации
DELETE/channels/{id}Удалить канал — только в панели (вставка на сайте перестаёт работать)

Узкие ручки безопаснее широкого PATCH: скрипт, который раз в месяц меняет акцентный цвет, не затрёт блоки витрины. Что можно прислать в каждое поле, отвечает /channels/schema.

Ключу нужно отдельное разрешение. Управление каналами не входит в «Чтение и редактирование»: витрина видна всему интернету, и ключ синхронизации цен не должен её трогать. При создании ключа включите «Управление витриной и виджетами», а чтобы ключ мог ещё и включать канал — подопцию «и публиковать». Без них придёт 403 с объяснением, чего не хватает. Удалять каналы ключом нельзя никогда — только в панели.

Сотрудникам застройщика права выдаются в CRM → Настройки → Команда: «Витрина» — собирать и менять каналы, «Публикует» — включать их. Маркетолог собирает, руководитель публикует.

В ответе приходят embedCode — готовая строка для вставки на сайт, previewUrl — адрес предпросмотра, apiUrl — корень публичного API канала, stats — показы и заявки за 30 дней и updatedAt — когда канал последний раз меняли или включали.

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

Квиз — отдельная запись проекта CRM (ниже), витрина на неё ссылается: quizId — кнопка и адрес /quiz, floatingQuizId — плавающий чат на страницах витрины. on: true у витрины без квиза заводит ей квиз со стандартным набором шагов. Кнопка и /quiz работают только у опубликованного квиза того же проекта; иначе адрес /quiz отвечает 404 и пропадает из карты сайта витрины.

Свой домен витрины задаётся тем же полем domains, что и список доменов виджета: витрина открывается по нему, как только домен направлен на сервис (DNS и сертификат подключает поддержка).

Для витрины (kind: "showcase") обязателен slug — адрес вида v.domxml.ru/{slug}. Оформление блоков лежит в blocks: незаполненные поля считаются из карточки ЖК, поэтому пустую строку слать не нужно — она перекроет умолчание.

Опубликовать витрину не получится, пока не заполнены застройщик и ИНН в карточке ЖК, ссылка на проектную декларацию (blocks.legal.declarationUrl) и ссылка на политику обработки персональных данных (settings.policyUrl): по 214-ФЗ и закону о рекламе они обязательны.

Квизы и чат-боты

Квиз — запись проекта CRM, как фид: создаёте, настраиваете, получаете постоянную ссылку https://v.domxml.ru/q/{code} и код вставки на сайт. Режим steps показывает сценарий по шагам, chat — диалогом чат-бота; заявки, статистика и вставка у них общие. До 20 квизов на проект CRM. Права и разрешения ключа — как у каналов: «Управление витриной и виджетами», публикация — подопцией «и публиковать»; удаление — только в панели. Обзор для маркетолога — страницы квиза и чат-бота.

МетодПутьОписание
GET/quizzes?crm={id}Квизы проекта, лимит, проект (crm: publicId, name, canPublish, customSteps) и его ЖК (complexes)
GET/quizzes/catalog?crm={id}&complexIds=1,2Что можно выбрать для этих проектов: шаги, наборы, блоки чата, закрытия, значки, раскладки, темы, лимиты, текст про свои вопросы
POST/quizzes?crm={id}Создать — выключенным; complexIds обязательно
GET/quizzes/{id}Квиз целиком: поля, url, embedCode, inlineCode, liveComplexIds, статистика за 30 дней
PATCH/quizzes/{id}Только присланные поля; объекты сливаются с прежними, null у поля — убрать
POST/quizzes/{id}/publishОпубликовать: нужны живые проекты и ссылка на политику обработки ПД
POST/quizzes/{id}/unpublishСнять: ссылка показывает заглушку, вставка не работает
GET/quizzes/{id}/embedСсылка и код вставки: плавающая кнопка и блок
GET/quizzes/{id}/stats?days=30Воронка по дням (1–365 дней)
GET/quizzes/{id}/logКто, когда и через что менял квиз (последние 100)
GET/quizzes/{id}/previewHTML предпросмотра — и у выключенного квиза; ?embed=1 — окно чата. Заявка из предпросмотра не уходит
POST/quizzes/{id}/previewПредпросмотр черновика: тело — несохранённые поля (как у PATCH, те же проверки), страница собирается без записи
POST, DELETE/quizzes/{id}/images/{slot}Картинка: cover, background или avatar
DELETE/quizzes/{id}Удалить — только в панели

Поля

ПолеЧто это
titleНазвание в панели и в ленте CRM («Заявка из квиза: …»), до 120 знаков
complexIdsПроекты: свои ЖК проекта CRM и ЖК агентских программ, до 20. Один — квиз привязан к нему, несколько — первый шаг «Какой интересует», заявка уходит в выбранный (при «Пока не знаю» — в первый)
modesteps — пошагово, chat — чат-бот
presetНабор шагов для steps: short, standard, detailed — свой у каждого вида проекта; у нескольких видов наборы объединяются
blocksБлоки диалога для chat по порядку: choose, object, rooms_budget, area_floor, timing_pay, mortgage, invest, question. Пусто — набор по умолчанию для вида проекта
stepsСвои шаги вместо набора: {"key"} из каталога или {"key": "c_…", "custom": true, "type": "single"|"multi", "text", "options": [2–8], "optional"}, до 12. Только если у проекта их включила поддержка (customSteps), иначе 400
closing{type, title, bonus, minutes} — закрытие, ниже
content{heading ≤120, subheading ≤300, advantages, cover, background}; advantages — до 4 пунктов {icon, text ≤80}, значки: percent, key, home, shield, clock, gift, star, check, ruble, map, car, tree
design{theme: light|dark|auto, color: "#RRGGBB", layout: cover-left|center|fullscreen, start: auto|button, startStyle: solid|soft|outline|arrow|pulse, startText: ≤40} — start: button: квиз открывается кнопкой
bot{name ≤40, avatar} — для чата; по умолчанию — название проекта и логотип застройщика
floatingПлавающая кнопка: {on, text ≤40, position: right|left, delay: 0–120} (секунды); цвет — design.color
settings{policyUrl, consentCheckbox, consentText, phone}; чего нет — берётся из витрины, где стоит квиз
domainsСайты, где разрешена вставка; пусто — любой сайт. Домены витрин с этим квизом разрешены всегда
metrikaIdНомер счётчика Яндекс Метрики для целей

Ссылки на картинки и политику — https:// или свой путь /uploads/…. Неизвестное поле, блок или шаг, который не подходит виду проекта, — 400 с объяснением, а не молчаливый пропуск.

curl -X POST "https://domxml.ru/api/v1/quizzes?crm=CRM_ID" \
  -H "Authorization: Bearer dxk_КЛЮЧ" -H "Content-Type: application/json" \
  -d '{
    "title": "Подбор квартиры — реклама VK",
    "complexIds": [1234567],
    "mode": "steps",
    "preset": "short",
    "closing": { "type": "bonus_form", "bonus": "Скидка 2% при бронировании" },
    "content": { "advantages": [{ "icon": "key", "text": "Ключи в 2027 году" }] },
    "design": { "theme": "auto", "color": "#2E5BFF", "layout": "cover-left" },
    "settings": { "policyUrl": "https://ваш-сайт.ru/privacy" }
  }'

Закрытия

closing.typeЧто видит человек
pick_formПодборка до трёх объектов и форма: имя, телефон. По умолчанию
bonus_formТо же с бонусом; bonus обязателен (до 120 знаков) и закрепляется за заявкой
callback«Перезвоним за N минут»: телефон, имя необязательно, без подборки; minutes — 5–240
messengerПодборка и выбор, куда прислать: Telegram, WhatsApp, MAX или звонок — ответом messenger
viewingЗапись на просмотр: день из ближайших десяти и время — ответом viewing
email_pickПодборка на почту: почта обязательна, плюс телефон

Тексты закрытий готовые, title меняет заголовок. Контакты — всегда последний шаг, в steps и blocks их не перечисляют.

Вставка на сайт

<!-- плавающая кнопка -->
<script src="https://v.domxml.ru/s/quiz-embed.js" data-quiz="CODE" async></script>

<!-- блоком в странице -->
<div id="dx-quiz-CODE"></div>
<script src="https://v.domxml.ru/s/quiz-embed.js" data-quiz="CODE" data-target="#dx-quiz-CODE" async></script>

Квиз открывается в рамке с v.domxml.ru, поэтому стили сайта его не задевают. Загрузчик передаёт в квиз адрес страницы и utm-метки, а цели — в Метрику сайта: атрибут data-metrika или metrikaId квиза. Цели: quiz_view, quiz_start, quiz_step_N, quiz_contact, quiz_lead.

Публичные ручки квиза

Их вызывают страница квиза и загрузчик. Авторизации нет — вместо неё код квиза и список domains (сверяются Origin, Referer и заголовок окна вставки). Выключенный и удалённый квиз отвечает 404.

МетодПутьОписание
GET/api/public/v1/q/{code}/configНастройки кнопки: allowed, mode, text, position, delay, color, bot, metrika
POST/api/public/v1/q/{code}/event{"type": "view"|"start"|"contact"} — счётчик воронки, без персональных данных
POST/api/public/v1/q/{code}/leadsЗаявка: name, phone, email, complexId, quiz: [{key, question, answer}], page, utm, consent, company, ft

Антиспам и лимиты заявок — как у формы канала: ловушка company, время заполнения ft, 10 заявок в час с адреса и 5 в сутки с телефона. Ответов — до 20, ответ — до 300 знаков, меток — до 10 по 200 знаков.

Статистика

GET /api/v1/quizzes/42/stats?days=30

{
  "days": 30, "views": 1240, "starts": 612, "contacts": 288, "leads": 97,
  "startRate": 49.4, "contactRate": 47.1, "conversion": 7.8,
  "byDay": [{ "day": "2026-10-01", "views": 51, "starts": 24, "contacts": 11, "leads": 4 }]
}

startRate — начали из открывших, contactRate — дошли до контактов из начавших, conversion — заявки из показов, в процентах; без базы — null.

Заявка из квиза создаёт клиента CRM с источником «Квиз» (режим chat — «Чат-бот»), в ленту пишутся ответы и обещанный бонус, в Битрикс24 уходят пары «вопрос: ответ», в вебхук lead.created — quizId, quizCode, quiz и bonus. MCP: инструменты quiz_* (документация).

Вебхуки

Вместо опроса API можно получать события запросом на свой адрес. Подписка создаётся в панели (API и MCP → Вебхуки) или по API.

МетодПутьОписание
GET/webhooks/eventsСписок событий, задержки повторов, порог отключения
GET/webhooksСвои подписки
POST/webhooksСоздать: url, events, необязательно name и complexIds
PATCH/webhooks/{id}Адрес, набор событий, ЖК, включить или выключить
DELETE/webhooks/{id}Удалить подписку
GET/webhooks/{id}/deliveriesЖурнал последних 50 доставок: попытки, коды ответа, ошибки
POST/webhooks/{id}/testПоставить в очередь пробное событие

События: lead.created, client.created, client.status_changed, apartment.booked, apartment.released, apartment.sold, deal.created, deal.lost (только по сделкам: отказ от интереса и снятая бронь сюда не попадают), complex.changed, channel.published; агентская программа — fixation.created, fixation.activated, fixation.extended, fixation.closed, fixation.confirmed (клиент ответил, работает ли с агентом), showing.requested, showing.confirmed, showing.done, showing.cancelled, booking.requested, booking.decided, commission.created, commission.updated (застройщику — по его ЖК, агенту и руководителю агентства — по их закреплениям).

Что приходит

POST https://ваш-сервер.ru/domxml-hook
Content-Type: application/json
X-DomXML-Event: lead.created
X-DomXML-Delivery: 8241
X-DomXML-Timestamp: 1789902000
X-DomXML-Signature: sha256=2f1c…

{
  "event": "lead.created",
  "createdAt": "2026-09-20T11:00:00Z",
  "data": {
    "clientNumber": 42,
    "isNewClient": true,
    "name": "Пётр",
    "phone": "+7 917 000-11-22",
    "source": "Витрина",
    "channelKey": "dxp_…",
    "complexId": 1234567,
    "apartmentId": 96,
    "quizId": null,
    "quizCode": null,
    "quiz": [],
    "bonus": null,
    "utm": { "utm_source": "yandex", "utm_campaign": "zarechye" }
  }
}

channelKey — ключ канала (виджета или витрины), с которого пришла заявка; utm — метки рекламы, которые прислала форма (не было — пустой объект). isNewClient: false — человек уже был в CRM, заявка легла в его карточку.

Заявка из квиза или чат-бота приходит с source «Квиз» или «Чат-бот», channelKey: null, номером и кодом квиза, ответами и обещанным бонусом:

"source": "Квиз",
"channelKey": null,
"quizId": 42,
"quizCode": "k7m2x9q4p1az",
"quiz": [
  { "key": "rooms", "question": "Сколько комнат нужно?", "answer": "2-комнатная" },
  { "key": "budget", "question": "Какой бюджет комфортен?", "answer": "7,5–9,5 млн ₽" },
  { "key": "pay", "question": "Как планируете оплату?", "answer": "Ипотека" }
],
"bonus": "Скидка 2% при бронировании"

Событие complex.changed несёт новую и прежнюю ревизию — по ним можно сразу запросить /changes?since=, не вызывая /version:

{
  "event": "complex.changed",
  "createdAt": "2026-09-23T09:00:00Z",
  "data": {
    "complexId": 1234567,
    "name": "ЖК «Приречный»",
    "rev": 43,
    "previousRev": 42
  }
}

Проверка подписи

Секрет выдаётся один раз при создании подписки. Подпись считается от строки «метка времени, точка, тело запроса» — метка внутри подписи не даёт переиграть старый запрос:

signature = "sha256=" + hmac_sha256(secret, timestamp + "." + raw_body)

Сравнивайте подписи функцией с постоянным временем сравнения и отклоняйте запросы старше пяти минут по X-DomXML-Timestamp.

Повторы

Ответ 2xx считается доставкой. При любом другом ответе или ошибке сети запрос повторяется через 1, 5, 30, 120 и 360 минут, после чего доставка помечается неудачной и остаётся в журнале. После 20 неудач подряд подписка выключается сама, а владелец получает уведомление — так отвалившийся навсегда адрес не копит очередь.

Отвечайте быстро: приёмнику даётся 10 секунд. Тяжёлую работу ставьте в свою очередь, а нам отвечайте сразу. Переходы по редиректам не выполняются, адрес должен быть публичным и на https.

CRM для застройщика

CRM — это проект: отдел продаж со своими ЖК, командой, клиентами, настройками, витринами и виджетами. У аккаунта может быть несколько проектов и приглашения в чужие. Доступ к ЖК и доступ к CRM независимы: менеджеру продаж шахматка не нужна, а редактор шахматки не видит клиентов.

Ключ без ограничения по ЖК работает с CRM так же, как пользователь в панели, в пределах прав владельца ключа в проекте («только свои», правка чужих, удаление, смена ответственного, задачи другим, администратор). Ключ с ограничением по ЖК к /crm не допускается — используйте MCP. {owner} в путях — публичный ID проекта (publicId из GET /crm/workspaces; у CRM, созданных до проектов, он совпадает с публичным ID владельца, поэтому старые интеграции работают). Клиент адресуется номером {number} в рамках проекта.

МетодПутьОписание
GET/crm/workspacesПроекты CRM пользователя: publicId, name, isOwn, role, rights, canChannels, canPublish — свои первыми
POST/crm/workspacesСоздать проект ({"name": "…", "kind": "sales|agency"}, до 120 символов; agency — агентство); создатель — владелец. PUT /crm/{owner}/agency — профиль агентства
PATCH / DELETE/crm/{owner}Переименовать (администратор проекта); удалить может только владелец и только пустой проект — без клиентов, открытых задач, ЖК и каналов, иначе 409
PUT/crm/{owner}/complexes/{complexId}Добавить свой ЖК в проект или перенести из другого (владелец ЖК и администратор проекта). ЖК входит в один проект; клиенты и история остаются в прежнем, каналы прежнего проекта этот ЖК больше не показывают
POST/crm/{owner}/teamПригласить в команду (администратор): {"who": "почта или публичный ID"} — только зарегистрированных; права по умолчанию — видит всех, правит, передаёт, ставит задачи
DELETE/crm/{owner}/team/{publicId}Убрать из команды (администратор; владельца — нельзя). POST /crm/{owner}/leave — выйти самому
GET/crm/{owner}/settingsПроект (project: publicId, name, isOwn), статусы, источники, этапы, команда, ЖК проекта
GET/crm/{owner}/clients?q&status&source&responsible&complex&stage&sort&limit&offsetСписок клиентов
POST/crm/{owner}/clientsСоздать клиента (name, phone|email или списки phones[]/emails[] — до 5 каждого, основной первым; messengers[telegram|max|wb], sourceId, complexIds, apartments[{apartmentId, stage, bookedUntil}])
GET / PATCH / DELETE/crm/{owner}/clients/{number}Карточка (phones[], emails[] — все контакты, phone/email — основной), правка (phones/emails целиком; одиночный phone/email меняет только основной, "" снимает его, последний контакт снять нельзя; phone вместе с phones — становится основным перед списком), в корзину (30 дней); POST …/restore
POST/crm/{owner}/clients/{number}/commentsЗаметка / звонок / встреча в ленту
POST/crm/{owner}/clients/{number}/tasksЗадача (text, assigneePublicId, dueAt); PATCH /crm/{owner}/tasks/{id}. dueAt — ISO 8601; без пояса — местное время CRM, одна дата — до 18:00 этого дня
GET/crm/{owner}/tasks?assignee=me|all&status=open|today|overdue|doneЗадачи
POST/crm/{owner}/tasksЗадача из раздела «Задачи» (text, dueAt, assigneePublicId, clientNumber — необязателен: задача может быть не привязана к клиенту)
GET/crm/{owner}/deals?complexId&stageId&responsibleId&purchaseType&q&staleDays&withClosedДоска сделок: этапы со счётчиком и суммой, сделки (клиент, квартира, этап, сумма, вид покупки). Сделка — квартира с суммой и видом покупки; интересы и брони клиента сюда не попадают
POST/crm/{owner}/dealsНовая сделка (clientNumber, apartmentId, amount, purchaseType, terms, force). Квартира прикрепится к клиенту, если её у него не было
PATCH/crm/{owner}/deals/{linkId}Этап (stageId), сумма, вид покупки, условия, заметка в ленту (comment), force — этап задаёт и стадию квартиры. stage (booked/deal/won/lost) меняет стадию напрямую, apartmentId переносит сделку на другую квартиру: старая возвращается в продажу, условия и дата сделки переезжают
POST/crm/{owner}/deals/bulkМассовые действия над отмеченными (ids + любое из stageId, purchaseType, amount, comment; force) → moved, failed[]
PUT/crm/{owner}/settings/deal-stagesЭтапы сделок (администратор CRM): stages[{id, name, color, kind: deal|won|lost, isDefault}]; нужны все три вида, по умолчанию — только deal
POST/crm/{owner}/clients/{number}/apartmentsИнтерес или бронь квартиры (apartmentId, stage, bookedUntil)
PATCH / DELETE/crm/{owner}/clients/{number}/apartments/{linkId}Стадия (booked | deal | won | lost), сумма, вид покупки, условия
POST/crm/{owner}/clients/bulkМассовые действия над выбранными (numbers, action: responsible | status | source | tags | task | comment | delete | restore)
GET/crm/{owner}/summary?period=week|month|quarter|year или ?from=YYYY-MM-DD&to=YYYY-MM-DDСводка: воронка, источники, сделки, задачи, брони, по менеджерам
GET/crm/{owner}/exportExcel «Клиенты» (администратор CRM)
POST/crm/{owner}/clients/{number}/pd-requestТребование по 152-ФЗ: {"kind": "access|rectify|delete", "receivedOn": "YYYY-MM-DD", "channel": "email|letter|phone|office|other", "note": "…", "deleteNow": true}. Срок ответа — в рабочих днях (сведения и удаление — 10, уточнение — 7). delete с deleteNow (по умолчанию) удаляет карточку и заявки сразу, без корзины (право «удаляет»)
GET/crm/{owner}/pd-requests?status=open|closed|allЖурнал требований (администратор CRM): срок, status (open, overdue, done, refused), кто записал и закрыл, итог
POST/crm/{owner}/pd-requests/{id}/closeЗакрыть: {"outcome": "done|refused", "note": "…"}; для отказа причина обязательна
POST/crm/{owner}/pd-requests/{id}/extendПродлить срок на 5 рабочих дней — один раз, с причиной (note); уточнение не продлевается
POST/crm/{owner}/pd-requests/{id}/delete-dataИсполнить отложенное требование об удалении (право «удаляет»)
PUT/crm/{owner}/settings/timezoneЧасовой пояс CRM (администратор CRM): {"timezone": "+5"} — целые часы от −12 до +14 или имя вроде Asia/Yekaterinburg; null — автоматически по ЖК. По нему «сегодня» у задач, дашборд, тихие часы и утренняя сводка; в settings — timezone: {value, auto, hours}
PUT/crm/{owner}/settings/team/{publicId}Права участника команды (администратор проекта): isAdmin, seeAll, editOthers, canDelete, canReassign, assignOthers, canChannels, canPublish, canAgentsView, canAgentsManage — только переданные поля; список members с правами приходит в settings, свои права — в rights у workspaces и settings
GET / POST/complexes/{id}/apartments/{aid}/clientsКлиенты квартиры из проекта, в который входит ЖК (только его команде); прикрепить существующего или создать нового

Смена статуса квартиры через PUT /complexes/{id}/apartments/{aid} при активной брони клиента отвечает 409 с полем crmBooking; повторите запрос с "force": true, чтобы снять бронь. Номер и имя клиента в crmBooking приходят только участнику его проекта CRM, остальным — null, а в crmName и holder — название проекта.

Агентская программа

Застройщик запускает программу по своему ЖК: условия (вознаграждение, шкала, правила закрепления клиента, что разрешено), участники — агенты и агентства (агентство — проект CRM вида agency). Агент закрепляет клиента по телефону, записывает на показ, просит бронь; застройщик решает в своей CRM. API подходит агентствам со своей CRM (amoCRM, Битрикс24 через Make или n8n): закрепление и статусы — ключом, события — вебхуками fixation.*, showing.*, booking.*, commission.*. Ключ с ограничением по ЖК работает только с условиями программ своих ЖК (/complexes/{id}/agent-program); закрепления, показы, бронь и начисления ему недоступны.

Агенту (свои закрепления; руководитель и администраторы агентства — все закрепления агентства):

МетодПутьОписание
GET/agent/programsПрограммы и приглашения: participantId, programId, status (invited | applied | active | blocked), via (лично или агентство), ЖК, вознаграждение, что разрешено
GET/agent/programs/{programId}Условия (с индивидуальными, если есть), правила закрепления, текст застройщика, участия с прогрессом по шкале (progress)
GET/agent/programs/{programId}/snapshot?profile=short|fullШахматка ЖК — публичный снимок (только при действующем участии и включённой программе)
POST/agent/participations/{participantId}/accept | decline | leaveПринять или отклонить приглашение, выйти из программы (за агентство — руководитель или администратор)
POST/agent/fixationsЗакрепить клиента: {"participantId", "name", "phones": [], "interest": "residential|other", "comment", "consent": true}. 201 — result: fixed | pending; 409 — code: own | taken | sales | quarantine и текст (чей клиент — не раскрывается). Если в ответе canRequestTransfer: true, клиента можно попросить передать вам: тот же запрос с "transfer": true и объяснением в comment (от 10 символов) → result: transfer, решает застройщик. Лимит проверок номеров в час — в условиях программы (429)
GET/agent/fixations?program&scope=open|closed&qЗакрепления: номер, состояние (pending | active | rejected | expired | released | won | lost), этап, срок, что можно продлить
GET/agent/fixations/{id}Карточка: история, показы, запросы брони, куда перенести (личное → агентство)
POST/agent/fixations/{id}/extend | release | moveПродлить (кнопкой в окне до конца срока или запросом застройщику — по условиям), снять, перенести в агентство ({"participantId"})
POST/agent/fixations/{id}/showingsЗапись на показ: {"startsAt": "ISO 8601 с поясом", "format": "office|site|online", "apartmentId", "comment"}; POST /agent/showings/{sid}/accept | cancel — принять время застройщика или отменить
GET/agent/fixations/{id}/slotsРасписание показов отдела продаж, если застройщик его задал: дни, слоты и сколько мест свободно (free). При расписании запись — только на startsAt свободного слота (400 — не из расписания, 409 — время уже заняли); с autoConfirm показ сразу подтверждён
POST/agent/fixations/{id}/bookingБронь объекта: {"apartmentId", "days", "comment"} — запрос застройщику или сразу, по условиям; POST /agent/bookings/{bid}/cancel
GET/agent/commissions?programНачисления и суммы по статусам (accrued | due | paid | cancelled)
POST/agent/fixations/{id}/confirm-maxСсылка на бота MAX для клиента (если бот подключён): клиент поделится номером, бот сверит его с номером в закреплении, и клиент подтвердит работу с вами. Ответ — в confirm закрепления и вебхуке fixation.confirmed

Застройщику ({owner} — проект CRM отдела продаж; право «Агенты: видит», решения — «Агенты: управляет»; показы подтверждает и «видит»):

МетодПутьОписание
GET / PUT/complexes/{id}/agent-programПрограмма ЖК: enabled, commission (ставка, шкала, byKind — по видам объектов, byBuilding — по корпусам, bonuses — бонусы на период), fixRules (в том числе transferRequests — запросы передачи клиента), allow (в том числе slots — расписание показов), termsText; участники; buildings — корпуса ЖК
POST/complexes/{id}/agent-program/participantsПригласить: {"kind": "user|agency", "who": "почта или ID"}; PATCH / DELETE …/participants/{pid} — статус, индивидуальная ставка, заметка
POST/complexes/{id}/agent-program/invite-linkСсылка-приглашение: {"enabled", "regenerate"}
GET/crm/{owner}/agents/fixations?state=pending|active|expiring|closed&complex&qЗакрепления проекта и счётчики; GET …/fixations/{number} — карточка с историей, показами и бронями
POST/crm/{owner}/agents/fixations/{number}/{action}approve (у запроса передачи — с reason: закрепление текущего агента снимается), reject (reason), extend (days), decline_extension, shown, verify (note), confirm_link (ссылка для клиента — в карточке confirmLink.url, 14 дней, один ответ; если бот MAX подключён — ещё confirmLink.maxUrl, клиент подтвердит номером телефона), release (reason)
GET/crm/{owner}/agents/showings?scope=upcoming|pastПоказы; POST …/showings/{sid}/confirm | reschedule | done | no_show | cancel
POST/crm/{owner}/agents/bookings/{bid}/approve | declineЗапрос брони: поставить обычную бронь CRM (days) или отклонить (comment)
GET / PATCH/crm/{owner}/agents/commissions, …/commissions/{id}Начисления: status (accrued | due | paid | cancelled), plannedAt, paidAt, корректировка amount с note
GET/crm/{owner}/agents/checks, /crm/{owner}/agents/summaryЖурнал проверок номеров по агентам; сводка «Агентский канал» за 30 дней

Клиенты агентов в CRM застройщика помечены полем agent и отбираются фильтром GET /crm/{owner}/clients?agent=1. Отметка «куплена» по клиенту агента с действующим закреплением создаёт начисление вознаграждения автоматически.

Примеры

Изменить цену квартиры

curl -X PUT https://domxml.ru/api/v1/complexes/12/apartments/345 \
  -H "Authorization: Bearer dxk_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"price": 5200000}'

Пересобрать фид Домклик

curl -X POST https://domxml.ru/api/v1/complexes/12/feeds/domclick/generate \
  -H "Authorization: Bearer dxk_ВАШ_КЛЮЧ"

Вызывать generate после каждой правки не нужно: фиды пересобираются сами раз в 3 часа, если в ЖК что-то поменялось. generate — чтобы площадка получила изменения сейчас.

Готовый фид всегда доступен по постоянной ссылке https://feed.domxml.ru/{type}/complex_{id}.xml. Прежний адрес https://domxml.ru/feeds/{type}/complex_{id}.xml отдаёт тот же файл — ссылки, уже переданные площадкам, продолжают работать.

Пагинация

Большинство списков отдаётся целиком. Постранично — там, где записей может быть много: параметры limit и offset.

Объекты ЖК (GET /complexes/{id}/apartments) приходят все сразу. Чтобы не качать их каждый раз, берите только изменения: /apartments/delta или /changes (синхронизация).

CORS

REST API (/api/v1) — для вашего сервера, а не для браузера. Запросы со страниц чужих сайтов браузер не пропустит: CORS открыт только панели DomXML. Да и не нужно: ключ dxk_ в коде страницы увидел бы любой посетитель. Для браузера есть публичное API с ключом канала dxp_ — оно отвечает Access-Control-Allow-Origin: * и отдаёт ETag наружу.

Коды ошибок

Всегда JSON вида {"detail": "текст"}.

КодКогда
400Запрос не имеет смысла: ревизии из snapshot?rev= ещё нет, отрицательный since, неизвестный via журнала, фиду VK или Директа не хватает данных (в тексте — чего), заявка без consent: true, когда согласие включено
401Ключ недействителен, отозван или истёк. После 30 неудачных попыток за минуту с одного адреса сервер минуту отвечает 401 и на верный ключ
403Не хватает уровня ключа (readonly пишет, editor удаляет), нет доступа к ЖК или ЖК вне списка ключа, путь закрыт для ключей, нет разрешения на каналы, нет права в ЖК или в CRM. В публичном API — запрос не с разрешённого домена канала
404Не найдено; в публичном API — ещё и выключенный или удалённый канал
409Конфликт с текущим состоянием: активная бронь CRM при смене статуса или удалении (в ответе crmBooking, повтор с force), объект куплен, фид выключен (generate), файл используется, проект CRM не пуст, время показа уже заняли
413Закончилось место в файловом хранилище
422Некорректное тело: тип, длина, диапазон, справочное значение — в detail массив ошибок по полям. Ещё — правила вида проекта: вид объекта или назначение здания не подходит проекту, второй объект в отдельном доме, фид площадки, недоступной виду (ctx.allowed), смена вида проекта, которой мешают объекты, здания или фиды
429Превышен лимит: публичное API (240 в минуту с адреса, 1200 на канал), заявки (10 в час с адреса, 5 в сутки с телефона), проверки фидов для импорта (20 в час), проверки номеров агентом (по условиям программы)

У 422 в detail — массив ошибок по полям:

{"detail": [{"type": "string_too_long", "loc": ["body", "salesPhone"],
             "msg": "Не длиннее 20 символов", "input": "…"}]}

При массовом создании в loc есть номер квартиры в массиве: ["body", "apartments", 3, "price"].

Фид площадки, недоступной виду проекта:

{"detail": [{"type": "value_error", "loc": ["body", "platform"], "input": "cian",
             "msg": "Циан принимает паркинги и коммерцию только в составе ЖК из своего каталога новостроек — у отдельного паркинга и гаражей доступны VK Реклама и Яндекс Директ",
             "ctx": {"allowed": ["vk", "direct"]}}]}

Общего лимита числа запросов по ключу dxk_ нет; массовые операции — до 500 объектов за запрос.

Безопасность