CRM · IMPORT

Object XML import

Bulk create and update agency objects from XML in the CRM cabinet.

Current for HATA XML + YRL profile (yandex_yrl_hata_v1), 2026-07-30

<?xml version="1.0" encoding="UTF-8"?>
<objects>
  <object external_id="sample-min-001">
    <type_code>apartment</type_code>
    <title>Two-room apartment, minimal example</title>
  </object>
  <object external_id="sample-full-001">
    <type_code>apartment</type_code>
    <title>3-room renovated apartment</title>
    <description>Bright apartment near metro.</description>
    <price>95000</price>
    <currency>USD</currency>
    <status_code>draft</status_code>
    <visibility>agency</visibility>
    <rooms>3</rooms>
    <images>
      <image>https://example.com/sample-listing-1.jpg</image>
    </images>
  </object>
</objects>

1. What XML import is

XML import lets a CRM agency bulk-create and update listings from a file or an HTTPS feed.

Objects are created only inside the current agency (X-Agency-ID / tenant context). Objects of another agency cannot be changed.

Access requires the objects.import permission. objects.update alone does not unlock bulk import.

v1 policy: upsert only — missing offers in a new feed do not delete or archive existing objects.

2. Supported formats

HATA XML v1 — recommended for full HATA features (root <objects>, <object external_id>).

Supported HATA import profile for Yandex Realty Language (yandex_yrl_hata_v1) — a subset of official YRL adapted for Uzbekistan.

This is not full Yandex Realty compatibility: Russian federal constraints may be ignored; HATA does not guarantee Yandex will accept the file.

Official YRL namespace: http://webmaster.yandex.ru/schemas/feed/realty/2010-06 (docs checked 2026-07-30).

3. YRL profile

  • Root <realty-feed>, <offer internal-id> → external_id.
  • Minimum: sale/rent; apartment, room, house, lot, garage.
  • Geography via HATA dictionaries; cities/districts are not auto-created from XML.
  • Currencies: UZS, USD. Area: m²; sotka → m² (1 sotka = 100 m²) without double conversion.
  • Unknown safe YRL tags → warning, not written to EAV.
  • Sample: /samples/yandex-yrl-hata-example.xml.

4. XML feeds by URL

  • CRM: «XML feeds» tab on /objects/xml-import.
  • Schedule: manual | every_6_hours | daily.
  • v1: public HTTPS URLs only (Basic Auth is not stored without an encryption key).
  • Unchanged checksum → status unchanged, no redundant updates.
  • Queue: RabbitMQ consumer; scheduler: python -m app.object_xml_feed_scheduler.main.

5. Limits

  • Default max file size: 5 MB (OBJECT_XML_IMPORT_MAX_BYTES).
  • Max objects per file: 500 (OBJECT_XML_IMPORT_MAX_ITEMS).
  • Encoding: UTF-8 only.
  • Extension: .xml; MIME: application/xml or text/xml.
  • One apply import per agency at a time; preview (validate) may run in parallel.
  • Live numeric limits also come from GET /api2_0/object/imports/config and limits_config in validate.

6. HATA XML format

Root: <objects>. Elements: <object external_id="…">. Namespaces and DTD are not supported.

If status/visibility are omitted, safe defaults draft and agency apply. Missing fields do not make an object public.

Unknown plain tags are errors. Unknown EAV codes are not created automatically.

ПолеОбязательноеТипОписаниеПример
external_id (атрибут)даstringВнешний ID в рамках агентстваagency-sku-123
titleдаstringНазвание объекта2-комн., Чиланзар
type_id или type_codeдаint / stringТип объекта из справочникаapartment
descriptionнетstringОписание
priceнетnumberЦена95000
currencyнетstring(3)ISO-код валютыUSD
status_id / status_codeнетint / stringПо умолчанию draftdraft
visibilityнетenumprivate|agency|public; по умолчанию agencyagency
deal_type_id / deal_type_codeнетint / stringТип сделкиsale
city_id / area_id / street_idнетintЛокация1
address / houseнетstringАдресЧиланзар
latitude / longitudeнетnumberКоординаты41.285
rooms / floor / floors_totalнетintСкалярные характеристики3
total_area / living_area / kitchen_areaнетnumberПлощади78.5
fields/field@codeнетEAVТолько существующие коды полейrenovation
images/imageнетhttps URLДо 30 на объект; SSRF-защитаhttps://…

4. Пример XML

Ниже и в файле /samples/object-xml-import-example.xml — минимальный и расширенный объекты. type_code и EAV-коды должны существовать в вашей базе.

5. Создание и обновление

  • Идентификация: (owning_agency_id, external_id).
  • Новый external_id → создание; существующий своего агентства → обновление.
  • Дубль external_id в одном XML → ошибка валидации.
  • Отсутствие объекта в новом XML ничего не удаляет и не архивирует.
  • Изменение external_id существующего объекта через XML не поддерживается.
  • Повтор одинаковых данных → unchanged; слот повторно не расходуется.
  • Обновление уже активного объекта слот не занимает.

6. Проверка перед импортом

  • Выберите XML → «Проверить файл» (validate).
  • Изучите preview: всего / новых / обновлений / ошибок / нужных и доступных слотов.
  • Исправьте критические ошибки; при listing_limit_reached запуск блокируется целиком.
  • «Запустить импорт» → status queued → polling detail до terminal status.
  • Скачайте CSV-отчёт при необходимости.

7. Статусы импорта

СтатусЗначениеДействие
validatedФайл проверен, объекты не измененыМожно запустить импорт, если can_apply
queuedИмпорт поставлен в очередьДождитесь running
runningИдёт обработкаPolling detail
completedУспешно без ошибок объектовСмотрите отчёт
completed_with_errorsЧасть объектов с ошибкамиСкачайте отчёт, исправьте XML
failedКритический сбой или все ошибкиПовторите после исправления

8. Ошибки

Ошибки объектов смотрите в таблице UI, GET …/errors или CSV report. Номер элемента — xml_index, путь — xml_path.

После исправления загрузите файл снова через validate.

КодПричинаЧто делать
xml_invalidПовреждённый или неверный XMLПроверьте UTF-8, корень <objects>, теги
xml_unsafeDTD/entities/опасная вложенностьУберите DOCTYPE и entity
file_too_largeФайл больше лимитаУменьшите файл (по умолчанию 5 МБ)
too_many_itemsБольше 500 объектовРазбейте файл
validation_failedОшибки в объектахСмотрите таблицу ошибок / отчёт
duplicate_external_idПовтор external_id в файле или конфликтСделайте ID уникальным в файле
listing_limit_reachedНе хватает слотов тарифаСнизьте публичные объекты или повысьте тариф
object_not_ownedexternal_id чужого агентстваИспользуйте свои ID
import_already_runningУже идёт applyДождитесь завершения
import_not_foundНет такого импортаПовторите validate
import_expiredИстёк TTL файлаЗаново проверьте файл
import_not_validatedНеверный статус для applyСначала validate
checksum_mismatchФайл изменилсяПовторите validate
unknown_fieldНеизвестный тегУдалите поле или смотрите контракт
unknown_eav_fieldНеизвестный EAV codeИспользуйте код из справочника
missing_requiredНет обязательного поляДобавьте external_id, title, type
invalid_enumНедопустимое значениеПроверьте visibility/status
type_not_foundТип не найденУкажите существующий type_code/type_id
status_not_foundСтатус не найденУкажите существующий status_code
image_forbiddenЗапрещённый URL изображенияТолько публичный https
image_fetch_failedНе удалось скачать изображениеПроверьте URL; объект всё равно может быть сохранён
redis_unavailableLocking service temporarily unavailableRetry later
queue_unavailableImport queue temporarily unavailableRetry later

9. Права доступа

Permission: objects.import — для всех API импорта и раздела CRM /objects/xml-import.

По умолчанию выдаётся ролям agency_admin, admin, manager, supervisor, platform_admin.

Скрытие пункта меню на frontend не заменяет проверку на backend (403).

10. Тарифные лимиты

Лимит max_active_listings применяется только к продавцам доски (board sellers). Для типичных CRM-агентств preview показывает applies=false и «Без лимита».

Слот занимают живые public/опубликованные объекты. draft/archived/deleted и другие неактивные статусы слот не занимают.

Если slot_required > available — импорт не запускается частично; код listing_limit_reached.

11. Изображения и безопасность

  • Только https; localhost, private/link-local/reserved IP запрещены.
  • Редиректы перепроверяются; таймаут и лимит размера ответа действуют.
  • Ошибка одного изображения не откатывает весь импорт — пишется warning/ошибка по объекту.

12. API

Все ручки требуют JWT, tenant context и objects.import. Prefix: /api2_0.

  • POST /object/imports/xml/validate — multipart file → preview + import_id (status validated).
  • POST /object/imports/xml — body {import_id} → {import_id, status: queued}; apply в фоне.
  • GET /object/imports — история агентства.
  • GET /object/imports/{id} — детальный статус и счётчики.
  • GET /object/imports/{id}/errors — ошибки по объектам.
  • GET /object/imports/{id}/report — CSV-отчёт.
  • GET /object/imports/config — лимиты для UI.