<?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 | По умолчанию draft | draft |
| visibility | нет | enum | private|agency|public; по умолчанию agency | agency |
| 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_unsafe | DTD/entities/опасная вложенность | Уберите DOCTYPE и entity |
| file_too_large | Файл больше лимита | Уменьшите файл (по умолчанию 5 МБ) |
| too_many_items | Больше 500 объектов | Разбейте файл |
| validation_failed | Ошибки в объектах | Смотрите таблицу ошибок / отчёт |
| duplicate_external_id | Повтор external_id в файле или конфликт | Сделайте ID уникальным в файле |
| listing_limit_reached | Не хватает слотов тарифа | Снизьте публичные объекты или повысьте тариф |
| object_not_owned | external_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_unavailable | Locking service temporarily unavailable | Retry later |
| queue_unavailable | Import queue temporarily unavailable | Retry 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.